简体   繁体   中英

std::vector and move semantics

To enable move semantics on a std::vector do I need to pass by value; so the compiler will not copy the element but just move them?

Example:

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

private:
    vector<string> private_data_;
};

to enable move semantics on a C++ stl vector

You have misunderstanding about the move semantic concept.

Thestd::vector itself is move constructable as it has the move constructor defined. You do not need to enable it explicitly, rather use it properly.

In the function

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

You are doing double copy. You need instead

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

or you might want

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

and for the second case, you call the function

setMyData(std::move(sourceData));

I would recommend either using 2 overload of that function or even use a generic one:

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

The templated one is a bit more complex since it uses a so called fowarding reference.

I suggest the following:

#include <utility>

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

And to init, you have two ways:

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

The good thing about this technique is that you don't have to write several overloaded methods, you can choose which way you want to pass your parameter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM