首先,让我说我已经阅读了有关 move 语义的许多问题。这个问题不是关于如何使用 move 语义的,而是在问它的目的是什么-如果我没有记错的话,我不明白为什么需要 move 语义。
背景
我正在实现一个重载类,出于这个问题的目的,它看起来像这样:
class B;
class A
{
private:
std::array<B, 1000> b;
public:
// ...
}
当需要使用 move 分配运算符时,我意识到我可以通过将
b
成员更改为std::array<B, 1000> *b;
来显着优化流程- move 可以只是删除和指针交换。这使我想到以下想法:现在,不应将所有非原始类型的成员都作为加速 move 的指针(在[1] [2]下更正))(在某些情况下,应该使用内存不能动态分配,但是在这些情况下,优化运动不是问题,因为没有办法这样做?
这是我实现以下目标的地方-为什么创建一个类
A
实际上只容纳一个指针b
,所以当我可以简单地指向整个A
类本身的指针时,以后进行交换就更容易了。显然,如果客户端希望 move 比复制快得多,则客户端应该可以进行动态内存分配。但是在这种情况下,为什么客户端不仅仅动态分配整个A
类?问题
客户端是否可以利用指针来完成语义给我们的一切 move ?如果是这样,那么 move 语义的目的是什么?
move 语义:
std::string f()
{
std::string s("some long string");
return s;
}
int main()
{
// super-fast pointer swap!
std::string a = f();
return 0;
}
指标:
std::string *f()
{
std::string *s = new std::string("some long string");
return s;
}
int main()
{
// still super-fast pointer swap!
std::string *a = f();
delete a;
return 0;
}
这是每个人都说的很棒的艰巨任务:
template<typename T>
T& strong_assign(T *&t1, T *&t2)
{
delete t1;
// super-fast pointer swap!
t1 = t2;
t2 = nullptr;
return *t1;
}
#define rvalue_strong_assign(a, b) (auto ___##b = b, strong_assign(a, &___##b))
很好-在这两个示例中后者都可能被认为是“坏样式”-意味着什么-但这真的值得双重连号所有麻烦吗?如果在调用
delete a
之前可能引发了异常,那仍然不是真正的问题-只需设置 guard 或使用unique_ptr
即可。编辑[1] 我刚刚意识到,对于像
std::vector
这样的类,这些类本身不需要使用动态内存分配并具有有效的 move 方法,因此这不是必需的。这只是使我的想法无效-以下问题仍然存在。编辑[2] 正如讨论中在注释和答案中提到的那样,这整整一点都没有意义。人们应该尽可能使用值语义,以避免分配开销,因为如果需要,客户端始终可以将整个事物移到堆中。
最佳答案
您的示例说明了这一点:您的代码不是异常安全的,并且使用了免费存储(两次),这可能很简单。要使用指针,在许多情况下(大多数情况下),您必须在免费存储区中分配内容,这比自动存储要慢得多,并且不允许RAII。
它们还使您可以更有效地表示不可复制的资源,例如套接字。
move 语义不是严格必需的,因为您可以看到C++已经存在40年了,而没有它们已经存在了40年。它们只是表示某些概念和优化的一种更好的方式。
关于c++ - 为什么要有 move 语义?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20305607/