views:

267

answers:

4

And how can I write my own array class to not need a default constructor for its elements? Right now, when I do the new [] to allocate space, I need a default constructor.

std::vector does not.

How do they do this magic?

A: 

I think, there will always be a default constructor, if the source code does not have it, the compiler will write it under the hood.

ArunSaha
The compiler will provide a default constructor for you *only* if you do not provide any constructor yourself. Take a look at my answer to this question -- in the first block of code, `struct X` has a constructor defined that takes an `int`. Because this ctor was defined by the user, the compiler will not generate a default ctor on its own, which results in a compiler error in `main`.
Dan
Not clear why downvote?! Per this link from GNU STL, http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a00738.html#a00a1d38b2d84de73741b233f537784e3, vector ''does'' have default constructor. If my understanding is wrong, please state it explicitly.
ArunSaha
The downvote wasn't mine, but the question was about how you can get away with creating a vector of elements, where the type of the element doesn't have a default constructor. You're correct that vector itself has a default constructor.
Dan
@Dan: Thank you for the explanation. My bad, I mis-understood the question, and was thinking completely in wrong direction :-(
ArunSaha
@ArunSaha: Probably didn't help that when you answered, the title was misleading: "Why doesn't std::vector need a default constructor?"
Dan
+4  A: 

You could allocate a block of bytes, then use placement new to make new instance of T (your parametric type) via copy constructor (not default constructor of course) when new items are pushed to the vector's back. This will not allow to to make "a vector of N default-initialized Ts" (which std::vector can make - which is why it does need T to have a default constructor for this purpose), but you could make vectors that start empty and can have Ts pushed onto them.

Alex Martelli
How do I allocate the space in the first place? malloc?
anon
@anon: Take a look at how `vector` does it... it uses an allocator, for example `new_allocator`. In my (old) Cygwin installation it works like this: `{ return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); }` Or `malloc_allocator` does it this way: `pointer __ret = static_cast<_Tp*>(malloc(__n * sizeof(_Tp)));`
Dan
+5  A: 

std::vector doesn't need the default constructor because it never uses it. Every time it needs to construct an element, it does it by using the copy constructor, because every time it has something to copy: either existing vector element or an element you yourself supplied for copying (explicitly or implicitly, by relying on a default argument)

You can write a class like that in exactly the same way: every time you need to construct a new element in your array, require the user to supply an element for copying. In this case constructing that original element becomes user's responsibility.

Every time it appears as if std::vector "requires" a default constructor from you, it simply means that somewhere you relied on a default argument of some of the vectors methods, i.e. it was you who tried to default-construct an element, not the vector. The vector itself, again, will never try to default-construct elements.

AndreyT
+1  A: 

std::vector only requires the element to have a default constructor if you use it in a way which requires the default constructor. So this code (stolen from a deleted answer) won't compile, because X does not have a default ctor:

#include <vector>

struct X
{
  X(int) {}
};

int main(void)
{
  std::vector<X> x(1); // vector of length 1, second argument defaults to X() !!
  return 0;
}

But if you write main like this instead:

int main(void)
{
  std::vector<X> x; // make empty vector
  x.push_back(X(1));
  return 0;
}

Then it works fine.

Dan
The first version will not compile, because `std::vector<X> x(1)` is a shorthand for `std::vector<X> x(1, X())`. It is in fact *you* who's implictly using the default constructor, not `vector`. Default arguments are evaluated "on your side".
AndreyT
@AndreyT: great point.
Dan