Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Passing STL Containers Make A Copy?

Tags:

c++

c++11

I can't remember whether passing an STL container makes a copy of the container, or just another alias. If I have a couple containers:

std::unordered_map<int,std::string> _hashStuff;
std::vector<char> _characterStuff;

And I want to pass those variables to a function, can I make the function as so:

void SomeClass::someFunction(std::vector<char> characterStuff);

Or would this make a copy of the unordered_map / vector? I'm thinking I might need to use shared_ptr.

void SomeClass::someFunction(std::shared_ptr<std::vector<char>> characterStuff);
like image 826
Mr. Smith Avatar asked Dec 28 '12 18:12

Mr. Smith


People also ask

Which containers do not allow duplicates?

A Set is a Collection that cannot contain duplicate elements.

Are STL containers implemented as templates?

They are implemented as class templates, which allows great flexibility in the types supported as elements. The container manages the storage space for its elements and provides member functions to access them, either directly or through iterators (reference objects with similar properties to pointers).

Is STL container thread safe?

The SGI implementation of STL is thread-safe only in the sense that simultaneous accesses to distinct containers are safe, and simultaneous read accesses to to shared containers are safe.


1 Answers

It depends. If you are passing an lvalue in input to your function (in practice, if you are passing something that has a name, to which the address-of operator & can be applied) then the copy constructor of your class will be invoked.

void foo(vector<char> v)
{
    ...
}

int bar()
{
    vector<char> myChars = { 'a', 'b', 'c' };
    foo(myChars); // myChars gets COPIED
}

If you are passing an rvalue (roughly, something that doesn't have a name and to which the address-of operator & cannot be applied) and the class has a move constructor, then the object will be moved (which is not, beware, the same as creating an "alias", but rather transferring the guts of the object into a new skeleton, making the previous skeleton useless).

In the invocation of foo() below, the result of make_vector() is an rvalue. Therefore, the object it returns is being moved when given in input to foo() (i.e. vector's move constructor will be invoked):

void foo(vector<char> v);
{
    ...
}

vector<char> make_vector() 
{ 
    ...
};

int bar()
{
    foo(make_vector()); // myChars gets MOVED
}

Some STL classes have a move constructor but do not have a copy constructor, because they inherently are meant to be non-copiable (for instance, unique_ptr). You won't get a copy of a unique_ptr when you pass it to a function.

Even for those classes that do have a copy constructor, you can still force move semantics by using the std::move function to change your argument from an lvalue into an rvalue, but again that doesn't create an alias, it just transfers the ownership of the object to the function you are invoking. This means that you won't be able to do anything else with the original object other than reassigning to it another value or having it destroyed.

For instance:

void foo(vector<char> v)
{
    ...
}

vector<char> make_vector() 
{ 
    ...
};

int bar()
{
    vector<char> myChars = { 'a', 'b', 'c' };
    foo(move(myChars)); // myChars gets MOVED
    cout << myChars.size(); // ERROR! object myChars has been moved
    myChars = make_vector(); // OK, you can assign another vector to myChars
}

If you find this whole subject of lvalue and rvalue references and move semantics obscure, that's very understandable. I personally found this tutorial quite helpful:

http://thbecker.net/articles/rvalue_references/section_01.html

You should be able to find some info also on http://www.isocpp.org or on YouTube (look for seminars by Scott Meyers).

like image 151
Andy Prowl Avatar answered Oct 04 '22 10:10

Andy Prowl