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

Is there any conventional way to be notified of STL move and copy constructors?

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

我在调试单线程应用程序时使用简单的 std::cout 输出来通知移动和复制(确保我自己的引用类型符合我的预期)。

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

我认为这可能有助于了解复制省略发生的确切位置、实际移动的位置(如果类型为 const,则不会衰减到复制操作)。

任何见解都会很有趣并受到赞赏。

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

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

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

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()获取拷贝构造容器的allocator。如果您没有在您的分配器中实现此功能,std::allocator_traits 只是 returns 您的分配器的副本。我也覆盖了此默认行为以输出消息。

容器move构造时,需要move构造allocator。所以我修改了 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

综上所述,不尽如人意"sort of"。 :-\