具有成员 std::vector 的移动语义

Posted

技术标签:

【中文标题】具有成员 std::vector 的移动语义【英文标题】:Move-semantics with a member std::vector 【发布时间】:2012-01-05 08:08:39 【问题描述】:

抱歉,如果之前有人问过这个问题,但据我了解,在 C++11 中,std::vector 有一个移动构造函数,因此在某些情况下,复制几乎没有任何成本,比如按值返回。但是,如果我有一个像这样的类,以 vector 作为成员变量:

class MyClass 
public:
    MyClass()  
    MyClass(const MyClass& rhs)  

    // other interfaces

private:
    std::vector<int> myvec;

    // implementation
;

并且有一个按值返回其中之一的函数,例如

MyClass somefunc() 
    MyClass mc;
    // fill mc.myvec with thousands (maybe even millions) of ints
    return mc;

mc.myvec 的移动构造函数是否会被调用,std::vector 的移动构造函数是否会被利用,即使 MyClass 本身对移动构造函数一无所知?还是会调用vector 的复制构造函数,然后将这数千(甚至数百万)的ints 一个一个复制?

【问题讨论】:

更好的是,任何实现 NRVO 的现代编译器都会忽略副本。 @K-ballo:取决于调用者写的内容。如果它是MyClass mc; /* other code */ if (something) mc = somefunc(); else mc = someotherfunc(); ,或者以其他方式使用函数的返回值作为赋值的RHS,那么NRVO 不会阻止复制赋值。如果您要编写依赖 NRVO 来实现基本效率的函数,则需要确保类可以有效地移动或可以有效地交换,以捕捉 NRVO 不适用的情况。 【参考方案1】:

如果您不编写任何显式复制或移动构造函数或任何复制或移动赋值运算符或析构函数,则默认提供的移动构造函数会逐个移动元素。详见12.8.9。

由于您定义了自己的复制构造函数,默认情况下您不会获得移动构造函数。要么定义一个(可能是= default),要么去掉显式的复制构造函数。

组合良好的类通常不需要任何自定义的 Big Five,而是依赖于提供它们的成员并使用默认版本。

【讨论】:

那么默认提供的move-constructor调用所有成员变量的move构造函数? @SethCarnegie:是的,确实如此。您可以通过创建一个包含unique_ptr 的类来尝试它,并从一个按值返回该类的函数对其进行初始化,这应该可以工作。 太棒了,非常感谢您的快速回答和澄清。时限届满,我会接受这个答案。

以上是关于具有成员 std::vector 的移动语义的主要内容,如果未能解决你的问题,请参考以下文章

移动语义的一切

首先创建字符串然后通过移动语义将其添加到向量或在向量中创建元素是不是具有内存效率?

在 return 语句中移动构造函数中的语义

移动语义+对成员成员变量的引用 - 解决方案和命名法?

发送具有 std::vector 成员的结构时出现分段错误

我是不是保证在移动向量后指向 std::vector 元素的指针有效?