是否有任何传统的方式来通知 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"。 :-\
我想知道是否有一种简单的方法可以在复制或移动 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"。 :-\