1

I have the following code snippet. I'd like it to fill up a vector with different instances of my Object object. That is, every time it adds an Object to the vector, it should call rand() and populate that object with a set of values unique to the other Object objects. Instead, this populates all the objects with the same values.


std::vector<Object> *objects;

Image::Image(unsigned nObjects)
{
  srand(2);
  objects = new std::vector<Object>();
  this->nObjects = nObjects;
  objects->resize(nObjects, Object(rand(), rand(), rand(), rand()));

  for(int i = 0; i < objects->size(); ++i)
    std::cout << objects->at(i).getX1() << std::endl;
}
audiFanatic
  • 2,296
  • 8
  • 40
  • 56

1 Answers1

2

That's because you're calling the parameterized constructor once to create a prototype object. After that the copy constructor is being called. As in the documentation:

If the current size is less than count, additional elements are appended and initialized with copies of value.

If you want to add N new items then AFAIK you need to use push_back (or preferably, emplace_back in C++11) in a loop:

#include <iostream>
#include <vector>

using namespace std;

struct Object {
    int alpha; 
    int beta;

    Object (int alpha, int beta) : alpha (alpha), beta (beta) {}
};

int main() {
    vector<Object> objs;
    int nObjects = 5;

    for (int i = 0; i < nObjects; i++) {
         objs.emplace_back(rand(), rand());
    }

    for (Object & o : objs) {
        cout << o.alpha << "," << o.beta << "\n";
    }
}

There are some routines in <algorithm> like generate_n to overwrite a range of items using the result of a function that is called repeatedly. But I don't think that's what you want here; as it requires the collection to already have objects in it that you overwrite. That's my impression. So when adding new items to the end when each object needs to be generated uniquely, I think emplace_back is the way to go.

As an additional note, always remember to reduce your example. If it's not about memory allocation, don't include a new. If two fields are enough, don't use four. And always if possible, submit your question in the form of a "Minimal, Complete, Verifiable Example" (like the code above).

Community
  • 1
  • 1
  • perfect, thank you. I ended up using push-back for legacy reasons. What's the advantage of emplace_back? – audiFanatic Oct 23 '14 at 04:19
  • @audiFanatic What happens with push_back is that you generate an object, then pass it to the method. The object has already been generated in memory somewhere. But the vector owns a block of memory of an array of objects into which the object must now be put. So it is copy-constructed into that slot in the vector. emplace_back actually constructs the object "in place"; so the only object construction which happens puts it right where it ultimately needs to go, all at once. C++11 is a big step forward in lots of ways so start using it asap! – HostileFork says dont trust SE Oct 23 '14 at 04:23
  • ah, I see. Yea, it's not my choice. I would be using it, but I'm collaborating with people using Visual Studio and I don't trust Microsoft to have implemented everything filly. I personally use g++ though. – audiFanatic Oct 23 '14 at 04:59
  • @audiFanatic There's probably little reason not to use the parts they have implemented. If it compiles it should work. It just won't always compile...so it's a subset of the full spec. [Here's a list](http://msdn.microsoft.com/en-us/library/vstudio/hh567368.aspx) for VS2010 and VS2012 and--relevant to this answer--a note about how there is [a limit to the number of parameters to emplace_back](http://stackoverflow.com/questions/19200183/emplace-back-and-vc-frustration) (which you can manually override). – HostileFork says dont trust SE Oct 23 '14 at 07:24