是否有任何传统方式可以通知STL移动和复制构造函数?

时间:2017-07-05 00:25:21

标签: c++ c++11 stl move-semantics

我想知道是否有一种简单的方法可以通知STL容器本身何时被复制或移动(无需处理修改或尝试重载STL方法的复杂性 - 因为我认为这很麻烦)。

当我调试单线程应用程序时,我使用简单的std::cout输出来通知移动和副本(确保我自己的引用类型符合我的意图)。

我已经考虑了一段时间,而且我只生成了真正的,非常愚蠢的想法(比如重载std :: move来生成实际的代码,以便它通知所有创建候选人的尝试移动 - 哈哈)。或者你可能重载真正的STL移动和复制构造函数,然后让它们调用真实的?

我认为这对于了解正在发生的复制精确位置,实际上正在移动的位置(如果类型为常量时不会衰减到复制操作)非常有用。

任何见解都会很有趣并且值得赞赏。

1 个答案:

答案 0 :(得分:4)

没有良好的方法来做到这一点。 HeroicKatora's comment是我所知道的唯一可能性:构建一个自定义分配器,在复制构造和移动构造时打印出消息。但是有问题......

要构建自定义分配器,请随时使用我的allocator boilerplate(无需版权,参考或链接)。这只是一个骨架分配器,可以帮助您入门。它没有什么特别的。

我用这个来为这个问题创建以下稻草人分配器:

template <class T>
class allocator
{
public:
    using value_type    = T;

    allocator() = default;
    allocator(allocator const&) = default;
    allocator(allocator&&)
    {
        std::cout << "container move construction\n";
    }

    template <class U> allocator(allocator<U> const&) noexcept {}

    value_type*  // Use pointer if pointer is not a value_type*
    allocate(std::size_t n)
    {
        return static_cast<value_type*>(::operator new (n*sizeof(value_type)));
    }

    void
    deallocate(value_type* p, std::size_t) noexcept  // Use pointer if pointer is not a value_type*
    {
        ::operator delete(p);
    }

    allocator
    select_on_container_copy_construction() const
    {
        std::cout << "container copy construction\n";
        return *this;
    }
};

template <class T, class U>
bool
operator==(allocator<T> const&, allocator<U> const&) noexcept
{
    return true;
}

template <class T, class U>
bool
operator!=(allocator<T> const& x, allocator<U> const& y) noexcept
{
    return !(x == y);
}

当容器副本构造时,需要调用std::allocator_traits<your_allocator>::select_on_container_copy_construction()来获取复制构造容器的分配器。如果未在分配器中实现此功能,std::allocator_traits只返回分配器的副本。我已经重写了这个默认行为以输出消息。

当容器移动构造时,需要移动构造分配器。所以我修改了allocator移动构造函数来打印出一条消息。

使用这种方法的问题是没有要求容器只移动或复制你的分配器一次!

使用vector作为示例容器,gcc为此驱动程序提供了理想的结果:

template <class T> using vector = std::vector<T, allocator<T>>;
template <class T> using deque = std::deque<T, allocator<T>>;

int
main()
{
    vector<int> v;
    std::cout << "Begin move\n";
    auto v2 = std::move(v);
    std::cout << "End move\n";
    std::cout << "Begin copy\n";
    auto v3 = v2;
    std::cout << "End copy\n";
}

gcc输出:

Begin move
container move construction
End move
Begin copy
container copy construction
End copy

Visual Studio为副本添加了一个无偿的移动构造:

Begin move
container move construction
End move
Begin copy
container copy construction
container move construction
End copy

LLVM的libc ++在移动结构上加倍:

Begin move
container move construction
container move construction
End move
Begin copy
container copy construction
container move construction
container move construction
End copy

总之,一种令人不满意的“种类”。 : - \