【问题标题】:std::vector and move semanticsstd::vector 和移动语义
【发布时间】:2021-12-12 15:04:56
【问题描述】:

要在std::vector 上启用移动语义,我需要按值传递吗?所以编译器不会复制元素而只是移动它们?

例子:

class data
{
public:
    void setMyData(vector<string> sourceData)
    {
        private_data_ = sourceData;
    }

private:
    vector<string> private_data_;
};

【问题讨论】:

  • 这能回答你的问题吗? What is move semantics?
  • 你可能只需要void setMyData(const vector&lt;string&gt; &amp; sourceData)。这里sourceData 是对您传递的向量的常量引用。不涉及复制。 setMyData 对向量做了什么? Mabe,这是一个XY Problem,请确保您需要告诉我们更多信息。
  • @Jabberwocky 纠正我,如果我错了,但是如果你通过 const 引用传递,如果我想要将内存从一个对象移动到另一个对象,那么 sourceData 怎么可能是一个空向量,因为我不想要复制矢量但只是移动它?
  • 我想我得到了你想要的。请确认: : 当你打电话给somedata.SetMyData(somevector); 之后somevector 应该是空的吗?

标签: c++ c++11 stdvector move-semantics c++-standard-library


【解决方案1】:

在 C++ stl 向量上启用移动语义

您对移动语义概念有误解。

std::vector itself is move constructable 定义了移动构造函数。您无需显式启用它,而是正确使用它。

在函数中

void setMyData(vector<string> sourceData)  // copy 1
{
   private_data_= sourceData; // copy 2
}

你正在做双重复制。你需要

void setMyData(vector<string> sourceData)  // copy 
{
   private_data_= std::move(sourceData); // move
}

或者你可能想要

void setMyData(vector<string>&& sourceData)  // only accept the rvalue
{
   private_data_= std::move(sourceData); // move
}

对于第二种情况,你调用函数

setMyData(std::move(sourceData));

【讨论】:

  • 嗨,“启用”我是想利用它,可能我没有正确表达自己。
  • 我要移动不复制原始向量可以为空之后这不是问题我拿起了 void setMyData(vector sourceData){private_data_=std::move(pirceData);}
  • @user1583007 “原始向量可以是空的,这不是问题”:如果是这样,您也可以使用第二个,您可以确保调用者只能移动构造或将右值传递给函数。 setMyData(std::move(sourceData)); 也可以用于第一个版本。
  • @Superlokkus 我想你没有阅读他上面的评论。我没有假设任何事情:“原始向量可以为空之后不是问题”:-> OP
  • @Superlokkus setMyData(foo) 清空foo 向量不一定是坏习惯,这取决于用例。如果之后实际上不再需要 foo 向量,这是最有效的解决方案,因为绝对不涉及复制。
【解决方案2】:

我建议使用该函数的 2 重载,甚至使用通用的:

#include <vector>
#include <string>

class data
{
public:
    void setMyData(const std::vector<std::string>& sourceData){private_data_=sourceData;}

    void setMyData(std::vector<std::string>&& sourceData){private_data_= std::move(sourceData);}

    template <typename T>
    void genericsetMyData(T&& source) {private_data_ = std::forward<T>(source);}

    private:
    std::vector<std::string> private_data_;
};

int main() {
    class data a,b,c,d;
    std::vector<std::string> s1,s2; const std::vector<std::string> s3;
    a.setMyData(s1);
    b.setMyData(std::move(s2));
    c.genericsetMyData(s1);
    d.genericsetMyData((std::move(s1)));
    d.genericsetMyData(s3);
}

模板化的比较复杂,因为它使用所谓的转发引用。

【讨论】:

  • 你确定吗?对于转发引用,我经常收到关于 std::forward 与 std::move 的相互矛盾的建议。
【解决方案3】:

我建议如下:

#include <utility>

class data
{
public:
    void setMyData(vector<string> sourceData)
    {
          private_data_ = std::move(sourceData);
    }
        
private:
    vector<string> private_data_;
};

而要初始化,您有两种方法:

vector<string> myStrings{"hello", "i am", "stringies"};
data mydata;

// Type 1: Give ownership
mydata.setMyData(std::move(myStrings)); // not a single copy, but myStrings is empty

// Type 2: Copy
mydata.setMyData(myStrings); // Copy once only, and myStrings is still valid

这种技术的好处是您不必编写多个重载方法,您可以选择要传递参数的方式。

【讨论】:

    猜你喜欢
    • 2013-10-17
    • 1970-01-01
    • 2012-01-05
    • 2015-09-19
    • 1970-01-01
    • 2013-10-15
    • 1970-01-01
    • 2018-02-02
    • 1970-01-01
    相关资源
    最近更新 更多