1

This is a pretty straight forward question. Is there a way to have a vector and initialize an element without constructing and then copying it?

class BigType
{
 // has a costly copy constructor
};

int main(void)
{
    using std::vector;
    vector<BigType> bigTypeVec;
    bigTypeVec.push_back(BigType(/*constructor from parameters*/));
    // This constructs a temp object, and then copies it to the new element.
}

Of course there are all sorts of work-a-rounds involving vectors of pointers, or instead of using a constructor, initialize an element's components with set functions, however I was wondering if there were a way to do it so that it can call the constructor on the element it allocates during push_back.

Edit: This question was marked as a duplicate, however I had viewed that page and the answers to his question hadn't answered mine. I want to know how to set the value of the element by constructing it once, rather then copy constructing a temporary object into the element. Emplace was a good way to do this.

bathtub
  • 426
  • 3
  • 15

4 Answers4

6

You could use std::vector<...>::emplace() or, if you want to append the object, std::vector<...>::emplace_back(), to construct the object in place. If you have to use C++03 this member function isn't available. As an approximation you could push_back() and empty object and then swap() your BigType into the corresponding location, assuming you could construct a small empty object.

Note that std::vector<...> isn't necessarily the best data structure if you have huge objects: if the reserved spaces runs out, the vector need to shuffle the objects around to make new space. You might want to use std::deque<...> instead, as it won't leave its objects put (unless you insert into the middle) while having similar access characteristics as std::vector<...>.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • It's not a big object actually, but its copy constructor is basically the code which is called the most often, across many iterations, and speed is an issue, so a vector of those objects calling a regular constructor then a copy constructor would slow things down significantly – bathtub Sep 18 '13 at 00:46
4

with C++11, yes.

bigTypeVec.emplace_back(BigType());

Here's some more info:

http://en.cppreference.com/w/cpp/container/vector/emplace_back

Aesthete
  • 18,622
  • 6
  • 36
  • 45
1

"Is there a way to have a vector and initialize an element without constructing and then copying it?"

Yes.

Consider placement new as a mechanism to side-step the use of a copy assignment and it's use of a temporary.


"Is there a way to have a vector..."

A vector can be built with elements created with the default constructor.

I believe it is possible to define BigType so that no element initialization is required during the bigTypeVec construction. In this way, declaring the vector (or even a simple array) will trigger no element constructor work. Consider these:

vector<BigType>  bigTypeVec;

or

BigType  bigTypeVec[MAX_BigTypeVecSize];

Note that the array requires BigType to provide a default constructor (or you to provide a big bunch of curly brace array initialzation).

However, I can imagine that you might find value for each BigType element to have an indication that it is or is not initialized.


" and initialize an element without constructing [a temp] and then copying it [, the temp, to the vector]?"

Placement new can then be used to construct the object in place. By passing the address of the desired bigTypeVec element you wish to initialize to the placement new, all the element constructor work will occur where (in memory) you want it. Consider something like:

vector<BigType>  bigTypeVec;

BigType* pBT = 0;

pBT = new (&bigTypeVec[0]  BigType(<param>); // placement new

pBT = new (&bigTypeVec[1]  BigType(<param>);

...

pBT = new (&bigTypeVec[n]  BigType(<param>);

Note the discard of pBT. Pointer is not used.


*"I was wondering if there were a way to do it so that it can call the constructor on the element it allocates during push_back."*

At this point, all that remains is to create the simplest class possible that inherits from std::vector() and re-impliments "push back", or perhaps a new method that supports your needs. These methods would seek the vector element that push-back would have found, and use the placement new similar to above.

2785528
  • 5,438
  • 2
  • 18
  • 20
  • Thanks! These were all great solutions. I considered placement new, but in my opinion, it is sort of like `goto` in that it should only be used as a last resort. Emplace, was the exact function I wanted to use. I agree that a default constructor that does little to know initialization and can be written over would save time, however I would still need to construct a temp object, and copy it into the element object, which can be avoided with emplace. I wouldn't be surprised if emplace used placement new in its implementation – bathtub Sep 19 '13 at 00:20
0

Are you sure about this?

    "This constructs a temp object, and then copies it to the new element."

As far as I know, it will directly create an object at the memory location. Return value optimization. Temporary will not be created.

Am I wrong?

NotAgain
  • 1,927
  • 3
  • 26
  • 42
  • Um, yup pretty much. Check out some of the other answers. But yeah, calling a constructor like that creates a temp object, which is then assigned to the allocated memory. Emplace is exactly what I needed – bathtub Sep 18 '13 at 00:48
  • Just trying to get my head around it. Usual way is cTor->Copy cTor->dTor, while calling cTor like this will call only: Copy cTor. And that Copy cTor is an expensive one in your code. Right? So you want to avoid that. – NotAgain Sep 18 '13 at 01:02
  • In my question, cTor -> Copy cTor -> dTor. using emplace, cTor -> dTor – bathtub Sep 18 '13 at 01:06