1

Since std::vector::push_back(obj) creates a copy of the object, would it be more efficient to create it within the push_back() call than beforehand?

struct foo {
    int val;
    std::string str;
    foo(int _val, std::string _str) :
        val(_val), str(_str) {}
};


int main() {
    std::vector<foo> list;

    std::string str("hi");
    int val = 2;

    list.push_back(foo(val,str));
    return 0;
}

    // or

int main() {
    std::vector<foo> list;

    std::string str("hi");
    int val = 2;

    foo f(val,str);
    list.push_back(f);

    return 0;
}
4
  • 5
    You have vector.emplace_back() to construct an object directly inside the vector. Your example will still make a temporary that is passed into the vector. Commented Mar 19, 2018 at 6:27
  • Even better option is to use list.emplace_back(val, str);. This will forward the arguments to the constructor and construct it "in place". Commented Mar 19, 2018 at 6:27
  • @super is slightly more accurate, but the idea is the same. Commented Mar 19, 2018 at 6:28
  • the reference en.cppreference.com/w/cpp/container/vector/emplace Commented Mar 19, 2018 at 6:28

3 Answers 3

3
list.push_back(foo(val,str));

asks for a foo object to be constructed, and then passed into the vector. So both approaches are similar in that regard.

However—with this approach a c++11 compiler will treat the foo object as a "temporary" value (rvalue) and will use the void vector::push_back(T&&) function instead of the void vector::push_back(const T&) one, and that's indeed to be faster in most situations. You could also get this behavior with a previously declared object with:

foo f(val,str);
list.push_back(std::move(f));

Also, note that (in c++11) you can do directly:

list.emplace_back(val, str);
Sign up to request clarification or add additional context in comments.

Comments

2

It's actually somewhat involved. For starters, we should note that std::vector::push_back is overloaded on the two reference types:

void push_back( const T& value );
void push_back( T&& value ); 

The first overload is invoked when we pass an lvalue to push_back, because only an lvalue reference type can bind to an lvalue, like f in your second version. And in the same fashion, only an rvalue reference can bind to an rvalue like in your first version.

Does it make a difference? Only if your type benefits from move semantics. You didn't provide any copy or move operation, so the compiler is going to implicitly define them for you. And they are going to copy/move each member respectively. Because std::string (of which you have a member) actually does benefit from being moved if the string is very long, you might see better performance if you choose not to create a named object and instead pass an rvalue.

But if your type doesn't benefit from move semantics, you'll see no difference whatsoever. So on the whole, it's safe to say that you lose nothing, and can gain plenty by "creating the object at the call".

Having said all that, we mustn't forget that a vector supports another insertion method. You can forward the arguments for foo's constructor directly into the vector via a call to std::vector::emplace_back. That one will avoid any intermediate foo objects, even the temporary in the call to push_back, and will create the target foo directly at the storage the vector intends to provide for it. So emplace_back may often be the best choice.

Comments

0

You ‘d better use

emplace_back(foo(val,str))

if you are about creating and pushing new element to your vector. So you perform an in-place construction.

If you’ve already created your object and you are sure you will never use it alone for another instruction, then you can do

push_back(std::move(f))

In that case your f object is dangled and his content is owned by your vector.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.