Question

So, I've always been a little fuzzy on C++ pointers vs. ... whatever the other one is called. Like,

Object* pointer = new Object();

vs.

Object notpointer();

I know that pointers are probably involved in the second one, but basically it's a not-pointer. (What's it actually called?)

Furthermore, I believe that for the first one, you have to call

delete pointer;

at some point once you're done with it, right? And the other one you don't need to worry about. I've read that the first is allocated on the heap, but the second is allocated on the stack, and goes away when the method returns.

However, what about when you're returning something (not a primitive) from a function?

A good example is written in Should I return std::strings?:

std::string linux_settings_provider::get_home_folder() {
    return std::string(getenv("HOME"));
}

By what I previously wrote, the string is allocated on the stack, and should be freed when the function returns, right? Yet nobody said anything about that, so I assume it works fine. Why?

In general, what's the difference between

return new std::string("pointer");

and

return std::string("not-pointer");

?

Also, assuming both work, what are the pros and cons of the two?

Was it helpful?

Solution

When you return by pointer, you need to return a dynamically allocated object the way that you show (i.e. returning a pointer to a stack object results in undefined behavior if it is dereferenced later). This creates a potential for memory leaks, because, like you have noted, that object needs to be deleted explicitly.

Returning by value, on the other hand (i.e. the second snippet) results in copying the object that you return from the stack object into the object that receives the return value:

std::string res = get_home_folder(); // std::string gets copied into res

Compilers can optimize this to avoid copying through return value optimization.

OTHER TIPS

I guess you didn't really want to write Object notpointer(); as this actually declares a function called notpointer returning an Object. If you meant Object notpointer; the entities in question are call values. Values are, indeed, allocated on the stack or, when the happen to be members of objects, embedded into the object.

When returning anything, the entity being returned is copied or moved into the location where the actual return value is expected. Once the return value is constructed, the local object, i.e., those on the stack, go out of scope and are destroyed. Given that the local objects are going away anyway, the compiler is allowed to elide the copy and construct the object immediately in the correct location, even if the copy constructor and/or the destructor have side effects.

The difference between your two return statements is

  1. When using new std::string("pointer") you get an object allocated on the heap and you return a pointer to the object. It is very easy to leak that pointer and you'd be better off to put it immediately into a suitable object, e.g., a std::unique_ptr<std::string>:

    return std::unique_ptr<std::string>(new std::string("pointer"));
    

    This way, the pointer won't be leaked. Of course, you'd also change the return type to be a std::unique_ptr<std::string> instead a std::string*. Note, that heap allocations are generally fairly expensive.

  2. When using std::string("value") you just return a local variable. There is a good chance that the copy will be elided and the return value is constructed immediately in the location where it should go. There is no need to look after any resources as all objects involved will be destroyed automatically. There is no explicit heap allocation and stack allocation are very fast.

Of course, in the given example the std::string actually needs to allocate its internal representation in both cases. If the pointer is returned, it is guaranteed that there is no additional internal allocation. On the other hand, when return a std::string value and it actually needs to be copied indeed, the internal memory may need to be allocated for the copy. That is, when returning large objects, possibly requiring lots of memory allocations, the approach returning a value runs the risk that it needs to be copied. With the current C++ the objects are, however, moved in the worst case, i.e., there isn't as much of a concern about copying the objects as there was in C++03.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top