将std :: vector传递给构造函数并移动语义

gho*_*ord 11 c++ c++11

在周末,我正在尝试刷新我的c ++技能并学习一些c ++ 11,我偶然发现了以下问题:我无法强制我的容器类正确使用移动构造函数:

我有一个构建器类,其定义如下:

class builder
{
   ...
   container build() const
   {
     std::vector<items> items;

     //... fill up the vector

     return container(items); //should move the vector right? wrong!
     //return container(std::move(items)); also doesn't work
   }
}
Run Code Online (Sandbox Code Playgroud)

类item和容器,定义如下:

class container
{
public:

    container(std:vector<item> items)
      : items_(items) // always invokes copy constructor on vector, never move
    { }

    container(container&& rhs)
    {
       ...
    }

    ...

private:
    std::vector<item> items_;

}

class item
{
public:
    //move .ctor
    item(item && rhs);
    item& operator=(item && rhs);

    //copy .ctor
    item(const item& rhs); //this gets called instead of move .ctor
    item& operator=(const item& rhs);

    ...
}
Run Code Online (Sandbox Code Playgroud)

现在我的代码只使用了

builder my_builder;
...
auto result = my_builder.build();
Run Code Online (Sandbox Code Playgroud)

这导致每个项目首先被构建然后被复制...

我应该怎么写以下classess不复制项目?我应该回去使用标准指针吗?

GMa*_*ckG 22

您的代码应更改为:

container(std:vector<item2> items) // may copy OR move
: items_(std::move(items)) // always moves
{}
Run Code Online (Sandbox Code Playgroud)

一般来说:如果你想要自己的东西副本,那么在该参数列表上制作该副本并将其移动到需要的位置.让调用者决定是否要复制或移动现有数据.(换句话说,你就在那里.现在只需移动你的数据.)

另外:return container(std::move(items));.之前我没有提到过,因为我错误地认为所有局部变量都是在return语句中自动移动的,但只有返回的值是.(所以这实际上应该有效:return items;因为container构造函数不是explicit.)

  • 函数`build`中的return语句应该改为`return container(std :: move(items));`否则会有一个不必要的项副本. (2认同)

Cod*_*gry 5

为您编写了启用了模板移动的类。研究它,你会得到它。

/// <summary>Container.</summary>
class Container {
private:
    // Here be data!
    std::vector<unsigned char>  _Bytes;

public:
    /// <summary>Default constructor.</summary>
    Container(){
    }

    /// <summary>Copy constructor.</summary>
    Container(const Container& Copy){
        *this = Copy;
    }

    /// <summary>Copy assignment</summary>
    Container& operator = (const Container& Copy){
        // Avoid self assignment
        if(&Copy == this){
            return *this;
        }
        // Get copying
        _Bytes = Copy._Bytes; // Copies _Bytes
        return *this;
    }

    /// <summary>Move constructor</summary>
    Container(Container&& Move){
        // You must do this to pass to move assignment
        *this = std::move(Move); // <- Important
    }

    /// <summary>Move assignment</summary>
    Container& operator = (Container&& Move){
        // Avoid self assignment
        if(&Move == this){
            return *this;
        }
        // Get moving
        std::swap(_Bytes, Move._Bytes); // Moves _Bytes
        return *this;
    }
}; // class Container
Run Code Online (Sandbox Code Playgroud)

我一直反对使用这样的值参数:

function(std:vector<item2> items)
Run Code Online (Sandbox Code Playgroud)

我总是使用:

function(const std:vector<item2>& items)
function(std:vector<item2>& items)
function(std:vector<item2>&& items)
Run Code Online (Sandbox Code Playgroud)

特别是对于较大的数据容器,很少:

function(std:vector<item2> items)
Run Code Online (Sandbox Code Playgroud)

对于较小的数据,从不使用向量。

这样,您可以控制发生的事情,这就是为什么我们使用C ++来控制一切。

  • 如果需要可写副本,只需将自己的const引用复制到变量中。
  • 如果您需要只读,则const reference可以防止新副本。
  • 如果要编辑原件,只需使用参考即可。
  • 当您感到懒惰时,请对小数据使用值参数。

显然,这完全取决于您在做什么。

我是一个自学成才的C ++开发人员。远非专家,尤其是C ++ ...语的人……但学习:)