# C++: Why is std::vector(std::auto_ptr(MYTYPE)) bad?

This topic is 3717 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I have just been converting much of my code to RAII. However, in a few places I have vectors of pointers that I would like to convert to auto_ptr. std::vector<std::auto_ptr<MYTYPE> > is exactly what I would want, except that I hear it doesn't work because std::auto_ptr doesn't fit the requirements for std::vector. AFAIK, the one requirement it doesn't meet is that it doesn't have a standard copy constructor (which requires that the copied item is const). To me it looks like it _should_ fit the requirements as long as I promise never to copy it, which I don't plan on doing. I understand that during inserts, erases and sometimes during resizes that the location of members in RAM change, which requires copy-constructing - but, shouldn't std::vector should be happy to use a non-const copy-constructor here since it's really a move or copy-construct + delete, hence the member being copied is already being treated as mutable. This would make std::vector<std::auto_ptr<MYTYPE> > correct for use in most applications, but still make copying it illegal. Secondly, if I can't use std::vector<std::auto_ptr>, is there a simple alternative? Thanks for all replies.

##### Share on other sites
You may not copy it yourself, but it may get copied quite alot inside std::vector, or any other std:: container for that matter. You can use boost::shared_pointer.

##### Share on other sites
Quote:
 Original post by yacwroyI understand that during inserts, erases and sometimes during resizes that the location of members in RAM change, which requires copy-constructing - but, shouldn't std::vector should be happy to use a non-const copy-constructor here since it's really a move or copy-construct + delete, hence the member being copied is already being treated as mutable.

A non-const copy-constructor isn't a copy-constructor. It's just a constructor (or perhaps a movement one). For reasons related to sloppy standards and annoying language semantics, std::vector implementations are allowed to rely on the invariant that a copy of the object can be made—which implies that the original and the copy are equally valid. In the case of std::auto_ptr, if the vector created a 'copy', then decided to dump the 'copy' and keep the original for whatever reason, the pointer would be destroyed and you'd lose data.

##### Share on other sites
To expand on the copying by std::vector: initially the vector will internally contain an array of objects with a certain length N. The moment you call push_back for the (N+1)th time the vector will allocate a new larger array, and copy everything from the first array to the new one. Since you don't know N, you cannot now when the copy constructors will get called. You could get around this by using the reserve() method of std::vector. But the suggestion to use shared_ptr is by far superior :)

##### Share on other sites
Quote:
 Original post by yacwroyTo me it looks like it _should_ fit the requirements as long as I promise never to copy it, which I don't plan on doing.

Ignore the previous posts: vector<auto_ptr> will do exactly the right thing on insertion, the copying on expansion will do the right thing, and all that. There's not problem there.

The problem is that operations on the vector may make temporary copies of elements of the vector (for example, std::sort, which takes a copy of an element as a pivot value then discards it). Next thing you know, you've lost data. To this end, the ISO C++ committee decided to break auto_ptr by making its copy constructor take a non-const reference, where standard containers have a const reference. The idea is that it will not compile, just in case you might want to perform an operation that might be unsafe.

The right thing to do is to use a refcounted pointer, not auto_ptr, with a standard library container.

##### Share on other sites
Quote:
 Original post by BregmaThe right thing to do is to use a refcounted pointer, not auto_ptr, with a standard library container.

Or use a boost pointer container.

##### Share on other sites
Quote:
 Original post by BregmaIgnore the previous posts: vector will do exactly the right thing on insertion, the copying on expansion will do the right thing, and all that.

Ah yes, you are right. I've never even considered this. Maybe I should start thinking a bit more ;-)

##### Share on other sites
Thanks.

shared_ptr is a good suggestion. Unfortunately, I'm not really a fan of shared_ptr though, and it's way too heavy for this use (not that that's too important).

I guess I better stay compliant and not just hope that a vector<auto_ptr> works. Thanks for confirming that it's illegal.

I've come up with a sort-of alternative, write my own template which encapsulates std::vector<T*> and calls delete on all pointers upon destruction.

template <typename T>class my::auto_vector {  public:    auto_vector() {}    ~auto_vector() {        for(std::vector<T*>::iterator it = m_items.begin(); it = m_items.end(); it++) {            delete (*it);        }    }    std::vector<T*> m_items;};

I guess I could also specify the std::vector functions that would be appropriate within auto_vector, and make m_items private. But it'll do for now.

I saw someone suggesting adding auto_vector to ::std
http://www.relisoft.com/resource/auto_vector.html
Not sure what is happening with this though.

Actually, I think I'll use that implementation eventually.

##### Share on other sites
One more thing I just thought of:

Even though when objects are to be moved by std::vector (because of insert / erase or resizing) they are mutable, they will still need to be copied with a const copy-constructor so that if the copy-constructor throws partway through the operation, the vector's original contents are still ok, and RAII is done / leaks & corruption are prevented.

Of course, this would require that erase / insert operations relocate the entire vector, which is still linear but worst-case (and worse than the specs at www.cplusplus.com state - don't know where the official ones are).

##### Share on other sites
Quote:
 Original post by yacwroyUnfortunately, I'm not really a fan of shared_ptr though, and it's way too heavy for this use (not that that's too important).

I'm sorry, that doesn't make sense.
And you don't need to be a "fan", you just have to realize that it's a good solution to the problem.

Moreover, instead of reinventing the wheel, you could just use boost's pointer container, as already suggested. it does pretty much what you were planning to do, but is much more likely to be 1) correct, 2) efficient.

1. 1
2. 2
3. 3
4. 4
Rutin
13
5. 5

• 12
• 15
• 9
• 14
• 10
• ### Forum Statistics

• Total Topics
632655
• Total Posts
3007675
• ### Who's Online (See full list)

There are no registered users currently online

×