有没有办法实现移动消除
Is there any way to achieve move elision
运行时:
struct Copy
{
Copy() {std::cerr << __PRETTY_FUNCTION__ << std::endl;}
Copy(const Copy & other) {std::cerr << __PRETTY_FUNCTION__ << std::endl;}
Copy & operator=(const Copy & other) {std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this;}
Copy(Copy && other) {std::cerr << __PRETTY_FUNCTION__ << std::endl;}
Copy & operator=(Copy && other) {std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this;}
~Copy() {std::cerr << __PRETTY_FUNCTION__ << std::endl;}
};
char buffer[1024];
template <typename Type>
Type * push(Type value)
{
return new(buffer) Type(std::move(value));
};
int main()
{
push(Copy());
return 0;
}
我得到以下输出:
Copy::Copy()
Copy::Copy(Copy &&)
Copy::~Copy()
有没有办法消除移动构造函数?
我希望使用 -O3 可以就地构建它,但根据我的测试,情况似乎并非如此。
有没有办法省略移动构造函数?[...]我希望使用 -O3,它会就地构建,
好吧,您正在显式调用移动构造函数...并且对象正在就地构建buffer
.为什么希望省略移动构造函数调用?
template <typename Type>
Type * push(Type value)
{
// invokes `Type::Type(Type&&)`
// vvvvvvvvvvvvvvvvvvvvvv
return new(buffer) Type(std::move(value));
// ^^^^^^^^^^^^^^^^
// casts `value` to `Type&&`
};
如果您尝试使用其他类型的值构造Copy
,您的问题会更有意义。 例如:
struct Copy
{
Copy(int) { std::cout << "INTn"; }
// ... other ctors ...
};
template <typename Type, typename Arg>
Type * push(Arg x)
{
return new(buffer) Type(std::move(x));
};
int main()
{
push<Copy>(1);
}
上面的代码打印:
国际
不调用移动/复制构造函数。
魔杖盒上的现场示例
我认为你不能这样做。 因为 elision 要求编译器对构造对象的位置有内在的知识。 有了这些信息,它就可以避免移动和复制,只需将对象放置在需要去的地方。 例如,当您从一个函数的堆栈中返回某些内容返回给另一个函数时,编译器可以省略移动/复制。
但是在您的情况下,放置 new 允许您将对象构造到任意缓冲区中。 该缓冲区实际上可以在任何地方,例如它可以在堆栈上(就像在您的情况下一样),也可以使用new
在堆上分配。 因此,编译器不会在此处省略移动/复制。
严格来说,这可以通过对代码进行一些分析来实现,因为编译器已经知道缓冲区在哪里,但我怀疑大多数编译器都实现了这一点。
请注意,您已经声明了一个字符指针数组而不是字符数组,因此如果这是您所期望的,缓冲区的长度超过 1024 字节
注意另请注意,显式调用std::move
可以防止省略
在这种情况下,您能做的最好的事情是创建一个就地构造函数或移动构造函数(如上所述)以将该对象构造到缓冲区中。 就地构造函数看起来像这样
template <typename... args>
void construct(std::in_place_t, Args&&... args) {
new (buffer) Type{std::forward<Args>(args)...};
}
使用具有完美参数转发的 emplace 函数。既然您即将开始新安置的冒险,还有几件事要说:
-
使用
std::aligned_storage_t<>
进行存储。它保证您的对象将正确对齐。 -
读取并使用放置
new
的返回值。在简单的情况下,它不会与您提供的地址不同。然而,标准允许它,并且在复杂的类层次结构中可能是这样。
更新的示例:
#include <iostream>
struct Copy
{
Copy() {std::cerr << __PRETTY_FUNCTION__ << std::endl;}
Copy(const Copy & other) {std::cerr << __PRETTY_FUNCTION__ << std::endl;}
Copy & operator=(const Copy & other) {std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this;}
Copy(Copy && other) {std::cerr << __PRETTY_FUNCTION__ << std::endl;}
Copy & operator=(Copy && other) {std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this;}
~Copy() {std::cerr << __PRETTY_FUNCTION__ << std::endl;}
};
std::aligned_storage_t<sizeof(Copy), alignof(Copy)> buffer[4];
template <typename Type, typename LegalStorage, typename...Args>
auto emplace(LegalStorage* buffer, Args&&...args) -> Type*
{
return new(buffer) Type(std::forward<Args>(args)...);
};
int main()
{
auto p1 = emplace<Copy>(buffer /* constructor arguments go here*/);
auto p2 = emplace<Copy>(&buffer[1]/* constructor arguments go here*/);
auto p3 = emplace<Copy>(buffer + 2/* constructor arguments go here*/);
auto p4 = emplace<Copy>(buffer + 3/* constructor arguments go here*/);
return 0;
}
- 运算符+ 的规范实现涉及额外的移动构造函数
- 如何为具有私有成员的派生类实现移动构造函数
- 在一个微不足道的可复制结构中,移动语义应该实现吗?
- std::sort 一个实现了移动构造函数的类
- 有没有办法实现移动消除
- 实现标记联合的移动构造函数
- 将函数及其实现移动到与主文件不同的文件(.hpp 和 .cpp)时,性能会受到很大影响
- 在deque实现中将1/2一个向量移动到另一个向量
- 如何使用继承(抽象基类)实现移动构造函数和移动赋值运算符
- 无法使用迭代器擦除矢量元素,矢量元素实现移动构造函数
- 交换对象不实现移动语义时的交换函数
- 是否可以实现std ::移动和清除功能
- 将执行从一个线程移动到另一个线程,以实现任务并行性并在将来调用
- 复制/移动操作符是否可以安全地用于实现复制/移动分配操作符
- 每次复制实现移动分配的非 const 对象时,我是否总是获得移动语义
- 使用 unique_ptr<> 实现移动构造函数和赋值
- 将类函数实现从 .h 移动到.cpp过程
- 如何实现大型非指针成员的移动构造函数
- 最佳C++移动构造函数实现实践
- Vector push_back移动实现