5

Say I have a class called Foo. Foo doesn't have a default constructor. It has a constructor Foo(int x, float y).

Bar is a container class. It contains a vector that contains instances of Foo.

Bar::Bar(int numberOfFoos, int x, float y) {

foovector.resize (numberOfFoos);
for(int i = 0; i < numberOfFoos; i++) {
   **read below**
}

at this point, I want to call the constructor of Foo and pass to it the parameters int x and float y. The constructor of Foo does different things depending on the value of x and y.

Let's say Foo had a default constructor, what exactly does the resize vector function do? Does it simply resize the vector without calling the default constructor? In other words, is space reserved for n elements of type Foo but they aren't initialized to anything??

What if it doesn't have one, like in this case?

in the for loop I want to initialize each Foo element in this way:

foovector[i].Foo(int x, float y);

but I can't call the constructor using the dot access operator in this way. I don't even know at this point if the constructor has already been called by the resize function or not.

Question is, how can I do it?

Another related question about vectors of classes:

In Foo there is a vector that holds floats. the float x parameter is the number of floats that it should hold. Foo's constructor has a line

arrayofFloats.resize (x);

But that means that the computer doesn't know beforehand the size of Foo. And each foo can have different size. Wouldn't it cause problems for a vector of Foo's? How can a vector of specific size be declared if each Foo can have different size?

Sorry for bad english, I hope it has been clear enough.

Thank you.

jazzybazz
  • 1,807
  • 4
  • 17
  • 21
  • possible duplicate of [C++ vectors of classes with constructors](http://stackoverflow.com/questions/3437017/c-vectors-of-classes-with-constructors) – Bo Persson Mar 18 '13 at 18:02

3 Answers3

6

Don't use resize to reserve space. Instead, use reserve:

foovector.reserve(n);                          // reserves memory only, no object
                                               // constructions take place
for (std::size_t i = 0; i != n; ++i)
{
    foovector.emplace_back(12 * i, i / 3.0);   // pushes a new Foo(12*i, i/3.0)
}                                              // at the back of the vector
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
1

If I understand this right, you want the Bar constructor to construct numerous instances of Foo within a vector with the same arguments to the Foo constructor each time. IF the Foo constructor works in such a way that the Foo objects will all be identical after construction, you can use std::vector::assign(size_type n, const value_type& val), where value_type in this case is Foo. If you call foovector.assign( numberOfFoos, Foo(x, y) ), the vector will construct one temporary Foo object and fill itself with numberOfFoos copies of that object. assign() also handles all your resizing needs.

But if the Foo constructor involves random behavior, static counters, or something else that causes successive calls to the constructor to result in different objects, copying is not what you want.

Your other question:

In C++, every type has a fixed size. (This is why polymorphism only works with pointers or pass-by-reference semantics.) Many classes, such as std::vector, manage additional memory which can grow or shrink as needed. This is all done behind the scenes with pointers. Additional memory, such as the data contained by a vector, is off in some other memory location and does not affect the actual size of the object. The vector methods size(), resize(), and reserve() work with that managed memory. So a Foo object is the same size no matter how many items are in its vector.

Sam Kauffman
  • 1,221
  • 11
  • 30
0

resize does initialise the new elements; specifically, it value-initialises a temporary object (using the default constructor, if it's a class type), then copy-initialises each element using that.

If it doesn't have a default constructor, or can't be copy-initialised, then you can't use resize.

However, you can use reserve to reserve memory without initialising any objects in it; and then use push_back or insert elements into that space. In C++11, you can also use emplace_back to avoid the need to copy elements:

foovector.reserve (numberOfFoos);
for(int i = 0; i < numberOfFoos; i++) {
   foovector.push_back(Foo(42, 1.23));   // C++03, requires copy constructor
   foovector.emplace_back(42, 1.23);     // C++11, doesn't require copy constructor
}

Regarding your extra question:

But that means that the computer doesn't know beforehand the size of Foo

Yes it does. A vector is a small object containing a pointer to some dynamically allocated memory; its size is fixed, and does not depend on how much memory it allocates.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • "If it doesn't have a default constructor, or can't be copy-initialised, then you can't use resize": I believe in C++11, it will value-initialise each element separately instead of copying (there's a separate overload for this case `void resize (size_type n);`) – Stephen Lin Mar 18 '13 at 18:14
  • Actually, if you're using the standard allocator, `T` still needs to be `CopyConstructible` in order to copy the existing elements to new storage if a reallocation is required for the `resize`, so your "If it doesn't have a default constructor, or can't be copy-initialised, then you can't use resize" is correct for the most part (if you use the stanard allocator), but "it value-initialises a temporary object (using the default constructor, if it's a class type), then copy-initialises each element using that." is definitely not: the new elements are value-initialized separately. – Stephen Lin Mar 18 '13 at 18:33
  • existing elements are _moved_ to new locations, not copied, so it needs to be MoveConstructible. You can have a vector of `unique_ptr` for example – Jonathan Wakely Mar 18 '13 at 18:37
  • @JonathanWakely I think I'm reading an old draft (n3242), mine says "Requires: `T` shall be `CopyInsertable` into `*this`."...was that updated in the final? I read somewhere that there are exception safety issues with moving during reallocation. – Stephen Lin Mar 18 '13 at 18:51
  • @JonathanWakely I'm reading `` (after preprocessing) and it uses `std::__uninitialized_move_if_noexcept_a`, so presumably it only calls `noexcept` move constructors and uses copy constructors otherwise? – Stephen Lin Mar 18 '13 at 18:58
  • If the move constructor might throw _and_ it's CopyConstructible then it copies, otherwise it moves (even if that could throw). So the requirement is MoveConstructible. N3482 says "_Requires_: `T` shall be `MoveInsertable` and `DefaultInsertable` into `*this`." (It was changed by [N3346](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3346.pdf)) – Jonathan Wakely Mar 18 '13 at 23:11
  • @JonathanWakely so that's actually newer than C++11 then? :D – Stephen Lin Mar 19 '13 at 03:15