c++ - 带有自定义分配器但没有其他参数的 std::function 构造函数有什么意义?

标签 c++ c++11 std-function

我正在尝试使用 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 分配给 myFunction3 时,分配是使用 function1 的分配器进行分配的。

这是正确的行为吗? 特别是,在案例 2 中,为什么要恢复使用默认的 std::allocator? 如果是这样,采用分配器的空构造函数有什么意义,因为分配器永远不会被使用。

这段代码我使用的是 VS2013。

我的 Allocator 类只是一个最小的实现,它使用 new 并在分配时注销

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 ,即使他们愿意,他们也无法真正存储分配器(类型删除分配器可能需要动态分配)。实际上,它们基本上是支持使用分配器构建协议(protocol)的空操作。

LWG 最近被拒绝了 an issue这会改变这种行为。

关于c++ - 带有自定义分配器但没有其他参数的 std::function 构造函数有什么意义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32596021/

相关文章:

c++ - 在 'break' 中使用 'for-loop' 对性能的影响

c++ - 如何将适当的 const_iterator 返回到非常量指针的集合?

c++ - 迭代器和标量对象之间的未定义行为有什么区别吗?

c++ - 如何在 C++ 中使用 std::function 实现策略模式

c++ - std::function 无法区分重载函数

c++ - boost.asio 和当前的网络 TS 最大的区别是什么?

c++ - 使用 const 字符串时创建默认构造函数

c++ - 确定 C++ 中包含文件的编译时存在

c++ - std::vector<int> 到 std::vector<enum>

c++ - 将 lambda 推导为 std::function<T>