是否有任何传统方式可以通知STL移动和复制构造函数?(Is there any conventional way to be notified of STL move and copy constru

编程入门 行业动态 更新时间:2024-10-27 21:24:12
是否有任何传统方式可以通知STL移动和复制构造函数?(Is there any conventional way to be notified of STL move and copy constructors?)

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

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

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

我认为这对于了解精确复制正在哪里,实际上正在移动的东西(如果类型为const则不会衰减到复制操作)可能是有用的。

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

I was wondering if there was a simple way to be notified of when STL containers themselves are copied or moved (without having to deal with the complexity of modifying or attempting to overload STL methods - as I imagine that to be cumbersome).

I use simple std::cout outputs to notify of moves and copies when I'm debugging single threaded applications (making sure my own reference types do what I intended).

I've been thinking about it for a while and I've only produced really, really, idiotic ideas (like overloading std::move to produce actual code so that it notifies of all attempts to create candidates for moving - lol). Or could you perhaps overload the real STL move and copy constructors and then make them invoke the real ones?

I'm thinking this could be useful for knowing where exactly copy elision is taking place, where things are actually being moved (and not decaying to a copy operation if the type is const).

Any insight would be interesting and appreciated.

最满意答案

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

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

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

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 move构造函数来打印出一条消息。

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

使用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

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

There is no good way to do this. HeroicKatora's comment is the only possibility I'm aware of: build a custom allocator that prints out messages when it is copy constructed and move constructed. But there are issues...

To build a custom allocator, please feel free to use my allocator boilerplate (no copyright, reference, or link needed). This is just a skeleton allocator to help you get started. It contains nothing special.

I've used this to create the following straw man allocator for this question:

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); }

When a container copy constructs, it is required to call std::allocator_traits<your_allocator>::select_on_container_copy_construction() to obtain the allocator for the copy constructed container. If you don't implement this function in your allocator, std::allocator_traits just returns a copy of your allocator. I've overridden this default behavior to output a message as well.

When a container move constructs, it is required to move construct the allocator. So I've modified the allocator move constructor to print out a message.

The problem with this approach is that there is no requirement that the container move or copy your allocator only once!

Using vector as an example container, gcc provides the ideal results for this driver:

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 outputs:

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

Visual Studio adds a gratuitous move construction to the copy:

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

And LLVM's libc++ doubles down on the move constructions:

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

In summary, an unsatisfactory "sort of". :-\

更多推荐

本文发布于:2023-08-03 08:39:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1385346.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:函数   有任何   传统   方式   通知

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!