使用自定义分配器但没有其他参数的 std::function 构造函数有什么意义?
What's the point of std::function constructor with custom allocator but no other args?
我正在玩弄 std::function 和自定义分配器,但是当我没有为函数提供初始仿函数时,它的行为并不像我预期的那样。
当我向构造函数提供自定义分配器但没有初始仿函数时,分配器从未被使用过,或者看起来是这样。
这是我的代码。
//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 按预期使用 allocator1 进行分配。
案例 2:在构造函数中为 myFunction2 分配了 allocator2,但是当分配了一个仿函数时,它似乎重置为使用默认 std::allocator 进行分配。(因此没有打印出关于分配的信息)。
案例 3:在构造函数中为 myFunction3 分配了 allocator3,但是当从 myFunction1 分配给 allocator3 时,分配是使用 function1 的分配器进行分配的。
这是正确的行为吗?
特别是,在案例 2 中,为什么要恢复使用默认值 std::allocator?
如果是这样,采用分配器的空构造函数有什么意义,因为分配器永远不会被使用。
这段代码我使用的是 VS2013。
我的分配器class只是一个最小的实现,它使用新的并在分配时注销
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
的分配器支持是...奇怪。
operator=(F&& f)
的当前规范是 std::function(std::forward<F>(f)).swap(*this);
。如您所见,这意味着 f
的内存是使用 std::function
默认使用的任何内存分配的,而不是用于构造 *this
的分配器。所以你观察到的行为是正确的,尽管令人惊讶。
此外,由于 (allocator_arg_t, Allocator)
和 (allocator_arg_t, Allocator, nullptr_t)
构造函数是 noexcept
,即使他们愿意,它们也不能真正存储分配器(类型擦除分配器可能需要动态分配)。照原样,它们基本上是支持使用分配器构造协议的空操作。
LWG 最近拒绝了 an issue 这会改变这种行为。
我正在玩弄 std::function 和自定义分配器,但是当我没有为函数提供初始仿函数时,它的行为并不像我预期的那样。
当我向构造函数提供自定义分配器但没有初始仿函数时,分配器从未被使用过,或者看起来是这样。
这是我的代码。
//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 按预期使用 allocator1 进行分配。
案例 2:在构造函数中为 myFunction2 分配了 allocator2,但是当分配了一个仿函数时,它似乎重置为使用默认 std::allocator 进行分配。(因此没有打印出关于分配的信息)。
案例 3:在构造函数中为 myFunction3 分配了 allocator3,但是当从 myFunction1 分配给 allocator3 时,分配是使用 function1 的分配器进行分配的。
这是正确的行为吗? 特别是,在案例 2 中,为什么要恢复使用默认值 std::allocator? 如果是这样,采用分配器的空构造函数有什么意义,因为分配器永远不会被使用。
这段代码我使用的是 VS2013。
我的分配器class只是一个最小的实现,它使用新的并在分配时注销
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
的分配器支持是...奇怪。
operator=(F&& f)
的当前规范是 std::function(std::forward<F>(f)).swap(*this);
。如您所见,这意味着 f
的内存是使用 std::function
默认使用的任何内存分配的,而不是用于构造 *this
的分配器。所以你观察到的行为是正确的,尽管令人惊讶。
此外,由于 (allocator_arg_t, Allocator)
和 (allocator_arg_t, Allocator, nullptr_t)
构造函数是 noexcept
,即使他们愿意,它们也不能真正存储分配器(类型擦除分配器可能需要动态分配)。照原样,它们基本上是支持使用分配器构造协议的空操作。
LWG 最近拒绝了 an issue 这会改变这种行为。