具有自定义分配器但没有其他args的std :: function构造函数有什么意义? [英] What's the point of std::function constructor with custom allocator but no other args?

查看:64
本文介绍了具有自定义分配器但没有其他args的std :: function构造函数有什么意义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在玩 std :: function 和自定义分配器,但是当我没有为函数提供初始函子时,它的行为却不尽人意。

I'm playing around with std::function and custom allocators but its not behaving as I expected when I don't provide the function with an initial functor.

当我向构造函数提供自定义分配器但没有初始函子时,该分配器从未使用过,或者看起来没有。

When I provide a custom allocator to the constructor but no initial functor, the allocator is never used or so it seems.

这是我的代码。

//Simple functor class that is big to force allocations
struct Functor128
{
    Functor128()
    {}

    char someBytes[128];

    void operator()(int something)
    {
        cout << "Functor128 Called with value " << something << endl;
    }
};

int main(int argc, char* argv[])
{
Allocator<char, 1> myAllocator1;
Allocator<char, 2> myAllocator2;
Allocator<char, 3> myAllocator3;
Functor128 myFunctor;

cout << "setting up function1" << endl;
function<void(int)> myFunction1(allocator_arg, myAllocator1, myFunctor);
myFunction1(7);

cout << "setting up function2" << endl;
function<void(int)> myFunction2(allocator_arg, myAllocator2);
myFunction2 = myFunctor;
myFunction2(9);

cout << "setting up function3" << endl;
function<void(int)> myFunction3(allocator_arg, myAllocator3);
myFunction3 = myFunction1;
myFunction3(19);
}

输出:

setting up function1
Allocator 1 allocating 136 bytes.
Functor128 Called with value 7

setting up function2
Functor128 Called with value 9

setting up function3
Allocator 1 allocating 136 bytes.
Functor128 Called with value 19

因此,案例1:myFunction1按预期使用分配器1进行分配。

So case1: myFunction1 allocates using allocator1 as expected.

case2:在构造函数中为myFunction2提供了allocator2,但是在分配函子后,它似乎重置为使用默认的std :: allocator进行分配。(因此,不打印有关分配的信息

case2: myFunction2 is given allocator2 in constructor but when assigned a functor it appears to reset to using the default std::allocator to make the allocation.(hence no print out about allocation).

case3:在构造函数中为myFunction3提供了allocator3,但是当从myFunction1分配给myFunction3时,分配是使用function1的分配器进行的。

case3: myFunction3 is given allocator3 in constructor but when assigned to from myFunction1 the allocation takes place using function1's allocator to make the allocation.

这是正确的行为吗?
特别是在情况2中,为什么要恢复使用默认的std :: allocator?
如果是这样的话,将分配器用作未分配器的空构造函数的意义是什么。

Is this correct behaviour? In particular, in case 2 why revert to using default std::allocator? If so what is the point of the empty constructor that takes an allocator as the allocator never gets used.

我将VS2013用于此代码。

I am using VS2013 for this code.

我的分配器类只是使用new并在分配时注销的最小实现

My Allocator class is just a minimal implementation that uses new and logs out when it allocates

template<typename T, int id = 1>
class Allocator {
public:
    //    typedefs
    typedef T value_type;
    typedef value_type* pointer;
    typedef const value_type* const_pointer;
    typedef value_type& reference;
    typedef const value_type& const_reference;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;

public:
    //    convert an allocator<T> to allocator<U>
    template<typename U>
    struct rebind {
        typedef Allocator<U> other;
    };

public:
    inline  Allocator() {}
    inline ~Allocator() {}
    inline  Allocator(Allocator const&) {}
    template<typename U>
    inline  Allocator(Allocator<U> const&) {}

    //    address
    inline pointer address(reference r) { return &r; }
    inline const_pointer address(const_reference r) { return &r; }

    //    memory allocation
    inline pointer allocate(size_type cnt,
        typename std::allocator<void>::const_pointer = 0) 
    {
        size_t numBytes = cnt * sizeof (T);
        std::cout << "Allocator " << id <<  " allocating " << numBytes << " bytes." << std::endl;
        return reinterpret_cast<pointer>(::operator new(numBytes));
    }
    inline void deallocate(pointer p, size_type) {
        ::operator delete(p);
    }

    //    size
    inline size_type max_size() const {
        return std::numeric_limits<size_type>::max() / sizeof(T);
    }

    //    construction/destruction
    inline void construct(pointer p, const T& t) { new(p)T(t); }
    inline void destroy(pointer p) { p->~T(); }

    inline bool operator==(Allocator const&) { return true; }
    inline bool operator!=(Allocator const& a) { return !operator==(a); }
};    //    end of class Allocator


推荐答案

std :: function 的分配器支持...很奇怪。

std::function's allocator support is...weird.

operator ==的当前规范F& f)是它确实执行 std :: function(std :: forward< F>(f))。swap(* this); 。如您所见,这意味着 f 的内存是使用默认情况下使用的 std :: function 分配的,而不是用来构造 * this 的分配器。因此,您观察到的行为是正确的,尽管令人惊讶。

The current spec for operator=(F&& f) is that it does std::function(std::forward<F>(f)).swap(*this);. As you can see, this means that memory for f is allocated using whatever std::function uses by default, rather than the allocator used to construct *this. So the behavior you observe is correct, though surprising.

此外,由于(allocator_arg_t,Allocator)(allocator_arg_t,Allocator,nullptr_t)构造函数是 noexcept ,即使他们想要存储它们也无法真正存储分配器(类型擦除分配器可能需要动态分配)。照原样,它们基本上是不存在的,用于支持uses-allocator构造协议。

Moreover, since the (allocator_arg_t, Allocator) and (allocator_arg_t, Allocator, nullptr_t) constructors are noexcept, they can't really store the allocator even if they wanted to (type-erasing an allocator may require a dynamic allocation). As is, they are basically no-ops that exist to support the uses-allocator construction protocol.

LWG最近拒绝了会更改此行为的问题

这篇关于具有自定义分配器但没有其他args的std :: function构造函数有什么意义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆