问题描述
我在玩 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构造函数有什么意义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!