为什么要移动语义? [英] Why have move semantics?

查看:258
本文介绍了为什么要移动语义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我先说我已经阅读了一些关于移动语义的问题。这个问题不是关于如何使用移动语义,它是在询问它的目的是什么 - 如果我没有错误,我不明白为什么移动语义是需要的。



< h2>背景

我正在实现一个重型类,为了这个问题,它看起来像这样:

  B类; 

class A
{
private:
std :: array< B,1000> b;
public:
// ...
}

它是时候做一个移动赋值运算符,我意识到我可以通过将 b 成员改为 std :: array< B ,1000>



这导致了以下想法:现在,

应该不是所有的非原始类型的成员都是指针加快运动(纠正下面[1] [2])(有一种情况下,内存不应该动态分配,但在这些



这里是我有以下实现 - 为什么创建一个类 A 这真的只是一个指针 b ,所以后来交换更容易,当我可以简单地指向整个 A 类本身。显然,如果客户端期望移动速度比复制速度快得多,则客户端应该可以进行动态内存分配。但是在这种情况下,为什么客户端不只是动态分配整个 A 类?



h1>

客户端已经不能利用指针做一切移动语义给我们?如果是,那么move语义的目的是什么?



移动语义:

  std :: string f()
{
std :: string s(some long string);
return s;
}

int main()
{
//超快指针交换!
std :: string a = f();
return 0;
}

指针:

  std :: string * f()
{
std :: string * s = new std :: string(some long string);
return s;
}

int main()
{
//仍然超快的指针交换!
std :: string * a = f();
delete a;
return 0;
}

下面是每个人都说的那么强大的任务:

 模板< typename T> 
T& strong_assign(T *& t1,T *& t2)
{
delete t1;
//超快的指针交换!
t1 = t2;
t2 = nullptr;
return * t1;
}

#define rvalue_strong_assign(a,b)(auto ___ ## b = b,strong_assign(a,& ___ ## b))

好 - 后两者在这两个例子中可能被​​认为是坏风格 - 无论什么意思 - 但它真的值得所有的麻烦与双和号?如果在调用删除之前可能抛出异常,这仍然不是一个真正的问题 - 只是保护或使用 unique_ptr

编辑[1] 我只是意识到这不是必要的类如 std: :vector 其使用动态内存分配本身并具有有效的移动方法。

编辑[2] 正如评论和答案中的讨论所提到的那样下面这个整点是很可笑的。应该尽可能多地使用值语义,以避免分配开销,因为如果需要,客户端总是可以将整个事务移动到堆。

解决方案

您的示例将其移除:您的代码不是异常安全的,它使用自由存储),这可以是非平凡的。要使用指针,在许多/大多数情况下,你必须在自由存储上分配内容,这比自动存储慢得多,并且不允许RAII。



还可以让你更有效地表示不可复制的资源,如套接字。



移动语义不是绝对必要的,你可以看到C ++存在<年 一段时间。它们只是表示某些概念和优化的更好方法。


Let me preface by saying that I have read some of the many questions already asked regarding move semantics. This question is not about how to use move semantics, it is asking what the purpose of it is - if I am not mistaken, I do not see why move semantics is needed.

Background

I was implementing a heavy class, which, for the purposes of this question, looked something like this:

class B;

class A
{
private:
    std::array<B, 1000> b;
public:
    // ...
}

When it came time to make a move assignment operator, I realized that I could significantly optimize the process by changing the b member to std::array<B, 1000> *b; - then movement could just be a deletion and pointer swap.

This lead me to the following thought: now, shouldn't all non-primitive type members be pointers to speed up movement (corrected below [1] [2]) (there is a case to be made for cases where memory should not be dynamically allocated, but in these cases optimizing movement is not an issue since there is no way to do so)?

Here is where I had the following realization - why create a class A which really just houses a pointer b so swapping later is easier when I can simply make a pointer to the entire A class itself. Clearly, if a client expects movement to be significantly faster than copying, the client should be OK with dynamic memory allocation. But in this case, why does the client not just dynamically allocate the whole A class?

The Question

Can't the client already take advantage of pointers to do everything move semantics gives us? If so, then what is the purpose of move semantics?

Move semantics:

std::string f()
{
    std::string s("some long string");
    return s;
}

int main()
{
    // super-fast pointer swap!
    std::string a = f();
    return 0;
}

Pointers:

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

And here's the strong assignment that everyone says is so great:

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

Fine - the latter in both examples may be considered "bad style" - whatever that means - but is it really worth all the trouble with the double ampersands? If an exception might be thrown before delete a is called, that's still not a real problem - just make a guard or use unique_ptr.

Edit [1] I just realized this wouldn't be necessary with classes such as std::vector which use dynamic memory allocation themselves and have efficient move methods. This just invalidates a thought I had - the question below still stands.

Edit [2] As mentioned in the discussion in the comments and answers below this whole point is pretty much moot. One should use value semantics as much as possible to avoid allocation overhead since the client can always move the whole thing to the heap if needed.

解决方案

Your example gives it away: your code is not exception-safe, and it makes use of the free-store (twice), which can be nontrivial. To use pointers, in many/most situations you have to allocate stuff on the free store, which is much slower than automatic storage, and does not allow for RAII.

They also let you more efficiently represent non-copyable resources, like sockets.

Move semantics aren't strictly necessary, as you can see that C++ has existed for 40 years a while without them. They are simply a better way to represent certain concepts, and an optimization.

这篇关于为什么要移动语义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆