首先,让我说我已经阅读了有关 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/

10-14 07:12