2

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_;
};
JeJo
  • 30,635
  • 6
  • 49
  • 88
user1583007
  • 399
  • 1
  • 5
  • 17
  • Does this answer your question? [What is move semantics?](https://stackoverflow.com/questions/3106110/what-is-move-semantics) – Superlokkus Oct 27 '21 at 10:09
  • 1
    You probably you just need `void setMyData(const vector & sourceData)`. Here `sourceData` is a constant reference to the vector you pass. There is no copying involved. What does `setMyData` do with the vector? Mabe this is an [XY Problem](https://xyproblem.info/), tu be sure you need to tell us more. – Jabberwocky Oct 27 '21 at 10:11
  • @Jabberwocky correct me if I am wrong but if you pass by const reference how can the sourceData be an empty vector if what I want is moving the memory from one object to another because I don't want to copy the vector but simply move it? – user1583007 Oct 27 '21 at 10:39
  • I think I'm getting what you want. Please confirm: : when you call `somedata.SetMyData(somevector);` should `somevector` be empty afterwards? – Jabberwocky Oct 27 '21 at 11:50

3 Answers3

4

to enable move semantics on a C++ stl vector

You have misunderstanding about the move semantic concept.

The std::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));
JeJo
  • 30,635
  • 6
  • 49
  • 88
  • Hi for "enable" I meant to take advantage of it, probably I did not express myself correctly. – user1583007 Oct 27 '21 at 10:26
  • I want to move not copy original vector can be empty after that is not a problem I picked up void setMyData(vector sourceData){private_data_=std::move(pirceData);} – user1583007 Oct 27 '21 at 10:34
  • You should add the const& overload, otherwise you have additional work for non rvalue calls, where there will always be a tempory created vector – Superlokkus Oct 27 '21 at 10:38
  • Since the OP did not show his/her intended usage, I would be very cautious with such assumptions plus that I think its bad practice. – Superlokkus Oct 27 '21 at 10:54
  • Oh you are right, my apologies, but it is still bad practice. – Superlokkus Oct 27 '21 at 11:15
  • 3
    @Superlokkus `setMyData(foo)` emptying the `foo` vector is not necessarily bad practice, it depends in the use case. If the `foo` vector is actually no longer needed afterwards, this is the most efficient solution as there is absolutely no copying involved. – Jabberwocky Oct 27 '21 at 11:55
2

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.

Superlokkus
  • 4,731
  • 1
  • 25
  • 57
1

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.

A. Smoliak
  • 438
  • 2
  • 17