views:

556

answers:

6

Why is that the single parameter constructor of std::list<T> requires T to be a default-constructible type? I mean the following code does not compile.

struct Foo { // does not have default constructor.
  Foo (int i) {} 
}
int main(void) {
  std::list<Foo> l(10);
}

It seems possible to use the construct and destroy idioms as they have already done in the std::vector, albeit with more book-keeping the list class.

On a related note, why not have the capacity function in list? You can argue that such a function would pay memory allocation cost up-front and eliminate the overhead later on as you push_back objects. At least it will make the interfaces of two STL sequence containers slightly more consistent.

+3  A: 

There is no general requirement that the type be default constructible - it must be copyable and assignable. Your code does not work because you try to create a list of 10 items - they have to be constructed somehow and so the default constructor must be used - but only in this specific case. If you created an empty list and added to it, there would be no such requirement.

The same is true for other containers - try compiling the following:

#include <vector>

struct A {
    A( int x ) : z(x) {}
    int z;
};

std::vector <A> a(10);

Regarding the second part of your question, I'd just observe that consistency of interface was not a prime design criterion for the standard containers - there is no intention, for example, that one type of container is a "drop-in" replacement for another. There is a good discussion of this in items 1 and 2 of Scott Meyers' book "Effective STL".

anon
Yes, std::vector does require that they be default constructible (at least if you call the appropriate constructor/function). If I do std::vector<Foo> v(5), what is v supposed to contain if Foo isn't default constructible?
Peter
I take back my words. vector does have that restriction on its single parameter constructor. Sorry for the confusion. I guess my question is then about why not have reserve and capacity functions in list.
Sumant
I also like the part of Neil's answer after the code snippet. I'll revisit Scott Meyers's book.
Sumant
A: 

Why is that the single parameter constructor of std::list requires T to be a default-constructible type?

Because this contructor - creates list with elements (number which you pass as parameter). Value of each element will be default. Also you could use constructor with two parameters, for create list with elements which will be initialized with second element value.

On a related note, why not have the capacity function in list?

It doesn't have sense, because cost of adding new elements to list is much little than in case with vector.

std::vector does not have such a restriction. My question is why not use the same techniques (create/destroy idioms) in the std::list as well?

It is not restriction. Because if you don't use such constructor, default initializer will not required. Same thing true for vector.

bb
+2  A: 

The reason is that, when you construct a list of n elements (where n is the parameter you used in the constructor), the list fills its structure of n elements with copies of T().

See sgi stl documentation for list.

Benoît
+2  A: 

Neil already answered the main question.

Also note that you need a default constructor when calling resize().

You can circumvent this by having a STL list of pointers to objects but I guess this already was obvious to you.

On a related note, why not have the capacity function in list? You can argue that such a function would pay memory allocation cost up-front and eliminate the overhead later on as you push_back objects. At least it will make the interfaces of two STL sequence containers slightly more consistent.

I guess the problem here is that STL lists allow cross-list splicing. If you want to allocate memory upfront, have a look at the Boost Pool Allocator.

Manuel
+4  A: 

std::list doesn't have a capacity function because it makes no sense; it never has to resize like a vector does. It's capacity is only limited by the available memory, which is not easily determined.

From what you asked for, I think you actually want reserve(). That's a one-off for vector because it (badly) needs such a thing; there's no particular requirement to make all functions consistent across all STL containers, especially when they make little sense for others.

You can accomplish the same effect using a custom allocator. As Manuel suggested, look at boost.

Peter
A: 

So your question is really "why not have reserve and capacity functions in list?"

The answer to that is that there's no reason to reserve memory in advance for list - adding new elements never requires a realloc & copy for existing elements, there's no requirement that the memory holding the contents of a list be contiguous, and iterators don't get invalidated when doing a list::push_back().

All of those are the reason for the existence of vector<>::reserve(), and having memory in reserve for new elements is why a vector<> will perform placement new into raw memory.

Michael Burr