tags:

views:

99

answers:

4

I'm an experienced coder, but am still relatively new to the STL, and have just come across this problem:

As far as I'm aware, STL containers aren't meant to copy the objects which they contain, or otherwise affect their lifecycles, yet experimentally I'm seeing different results.

In particular, string classes, which are meant to zero out the first character of their underlying storage upon destruction, are still accessible if they are stored in a container before they go out of scope. For instance, consider the following example:

using namespace std;

queue<string> strQueue;

const char *genStr(int i)
{
    ostringstream os;
    os << "The number i is " << i;
    strQueue.push(os.str());
    return strQueue.back().data();
}

void useStr()
{
    while(!strQueue.empty())
    {
        cout << strQueue.front() << endl;
        strQueue.pop();
    }
}

int main(int argc, char **argv)
{
    for(int i = 0; i < 40; i++)
    {
        printf("Retval is: %s\n", genStr(i));
    }
    useStr();

    return 0;
}

As the strings go out of scope when genStr() exits, I would expect the printf to just output "Retval is: ", or at the very least for the call to useStr() to give undefined results, as the memory was stomped on by the repeated allocations from the extra calls, yet both return the appropriate stored strings, without fail.

I'd like to know why this happens, but in lieu of that, I'd be happy just to know whether I can rely on this effect happening with any old object.

Thanks

A: 

What goes into the container is a copy of the object and not the actual object. Similarly what you get back is also a copy. You can access these objects as long as your container is in scope.

naivnomore
What you get back is not necessarily a copy, unless you copy it yourself. `int //reference to the first item`
UncleBens
+8  A: 

As far as I'm aware, STL containers aren't meant to copy the objects which they contain

Okay, let's stop right there. STL containers do copy their contents, frequently. They copy them when they're inserted, they copy them when the container is resized either automatically or explicitly, and they copy them when the container itself is copied. Lots and lots of copying.

I'm not sure where you got the idea that STL containers don't copy their contents. The only thing that I can think of that's even close is that if you insert a pointer into an STL container, it will copy the pointer itself but not the pointed-to data.

Also, there are no references involved in your code whatsoever, so I'm puzzled as to what the title of this question refers to.

Tyler McHenry
Thanks - I got the impression that STL containers store by reference instead of copying the data from the fact that all of the storage methods take references. In retrospect, it was a poor assumption to make, but in my defence it was quite late, heh.As to the references thing, I was assuming that the compiler was implicitly passing a reference to the queue when I call "strQueue.push_back(os.str().data()" - as push_back only accepts references, I still believe this to be the case, but I'd appreciate being corrected if I'm wrong
predakanga
In C++ a common practice is for functions and methods to take object parameters (i.e. things other than ints, floats, chars) by *const* reference. This avoids making a copy when calling the function, but it doesn't (and actually almost never) means that the function is going to hold on to a reference to that object. In a container situation, the container object will accepted the object to insert by const reference, and then copy it into its permanent storage. This results in one copy instead of two copies (one into the parameter, and then another into the storage).
Tyler McHenry
A: 

All the "STL" (I hate that term) collections store copies of the objects passed to them, so the lifetime of the object in the collection is completely independent of the original object. Under normal circumstances, the collection's copy of an object will remain valid until you erase it from the collection or destroy the collection.

Jerry Coffin
Out of curiosity, why do you hate the term "STL"?
Pedro d'Aquino
@Pedro: I haven't hated it, but it is kind of a bad name. The words standard, template, and library don't give you any indication of anything useful or relevant about the library, and make it seem like templates are some specialized technology, rather than something you should always use in your C++ apps.
Merlyn Morgan-Graham
@Pedro: because different people mean such different things by it, that it tends to lead to a lot of misunderstandings. Even exactly what words "STL" stands varies. Some people mean "STandard Library", other "Standard Template Library", and so on. Even then, if you mean standard template library, do you mean the library that was presented to the committee ~15 years ago, the parts of that library that were accepted into the standard, or the current library by that name? If you mean the standard library, which parts?
Jerry Coffin
@Jerry: According to Stepanov, "STL" means "Standard Template Library," so the people who say that STL means "Standard Library" might as well refer to a 911 as a Ferrari. http://www.stlport.org/resources/StepanovUSA.html
John Dibling
@John: As highly as I think of Alexander Stepanov, I don't think he's quite in a position to decree the sole interpretation of a particular TLA. Worse, even if he was, we're still left with at least three different interpretations to use.
Jerry Coffin
+5  A: 

STL containers aren't meant to copy the objects which they contain

The STL is all about making copies. It will make them when you insert objects, and will sometimes make them if the underlying storage gets resized. You may get broken code if the object you are copying becomes invalidated when your function goes out of scope (for example if you add a pointer to a local variable, rather than copying the local variable).

In your case, you aren't copying a reference to a string, you're copying a string. This copied string then exists in the scope of strQueue, so the behavior you are seeing is completely valid and reliable.

Here is another misunderstanding to clear up:

In particular, string classes, which are meant to zero out the first character of their underlying storage upon destruction

C++ doesn't tend to ever do that sort of thing. It would be a hidden cost, and C++ hates hidden costs :) The string destructor won't touch the memory because once the destructor has exited, the object no longer exists. Accessing it is undefined behavior, so the C++ implementation will do whatever is fastest and least wasteful in well defined code.

Merlyn Morgan-Graham
+1 for best answer, but one thing with the wording: "objects going out of scope" aren't objects anymore, just raw memory...
hjhill
@hjhill: Which happens first - the curly brace, or the destructor? If a tree falls in a forest... I'll fix the wording so there's no ambiguity tho :)
Merlyn Morgan-Graham