1

I know this question has been asked a lot in SO as in Object creation on the stack/heap? To my understanding if an object is stored in Stack it will get popped if the variable gets out of scope. But when it come to automatic storage it confuses me how is it not in heap. I've read that using new and delete in C++ is not recommended (or even evil is the choice of word), because it will introduce memory leak. So I device a test code like these

#include <iostream>
#include <string>

class Cat
{
public:
    Cat(const std::string& name)
    {
        this->name = name;
        std::cout << "construct Cat " << this->name << std::endl;
    }
    ~Cat()
    {
        std::cout << "destruct Cat " << this->name << std::endl;
    }
    void feed()
    {
        std::cout << "feed Cat " << this->name << std::endl;
    }
private:
    std::string name;
};

Cat createFelix()
{
    Cat garfield("Garfield");
    Cat felix("Felix");
    garfield.feed();
    felix.feed();
    return felix;
}

void getAndFeedFelix()
{
    Cat justFelix = createFelix();
    justFelix.feed();
}

int main()
{
    getAndFeedFelix();
    std::cout << "bla bla blah" << std::endl;
}

and it resulted like these

construct Cat Garfield
construct Cat Felix
feed Cat Garfield
feed Cat Felix
destruct Cat Garfield
feed Cat Felix
destruct Cat Felix
bla bla blah

so in my conclusion, the function createFelix() is called from getAndFeedFelix() which returned a Cat (which stored in stack), that supposed to be popped from the stack after the function return, but the object is destructed after getAndFeedFelix() is out of scope, because of the automatic storage mecanism. How can this happen? If automatic storage is using heap and reference counting then it might be possible. Is my logic wrong?

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Automatic storage is using the stack, not the heap – vsoftco Jan 15 '15 at 03:17
  • 3
    You should implement an instrumented copy constructor and assignment operator if you want to see all of the details. – Retired Ninja Jan 15 '15 at 03:17
  • 2
    "I've read that using new and delete in C++ is not recommended (or even evil is the choice of word), because it will introduce memory leak". Whoever said that hasn't worked on a real project. – R Sahu Jan 15 '15 at 03:19
  • 3
    @RSahu I think exactly the opposite, after you work on a real project you tend to recommend not using raw pointers but smart ones. – vsoftco Jan 15 '15 at 03:21
  • 1
    @vsoftco, use of heap memory is a tool in your toolbox. Once you learn how to use that tool, it's not scary. It's scary only if you come from a language in which memory is managed for you. – R Sahu Jan 15 '15 at 03:25
  • If stack is using LIFO why does after garfield is destructed, felix is still accessible? – Marcel Daryanto Jan 15 '15 at 04:12

1 Answers1

4

You have discovered Return Value Optimization (specifically named return value optimization).

This function:

Cat createFelix()
{
    Cat felix("Felix");
    return felix;
}

Cat justFelix = createFelix();

looks like it should create a Cat, copy it, and destroy it. But as an optimization, createFelix() actually creates felix in the memory owned by justFelix. So we just create one Cat, with zero copies. Everything here is on the stack.

So then:

void getAndFeedFelix()
{
    Cat justFelix = createFelix(); // creates a cat
    justFelix.feed();              // feeds a cat
}                                  // destroys a cat

Which is the output you see.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • How then you test in function `createFelix()` so the object `felix` is stored in stack? I refrain from using `return Cat("felix");` directly to avoid this optimization – Marcel Daryanto Jan 15 '15 at 03:48
  • @MarcelDaryanto Why do you need to test whether something is living on the stack? It is 100% guaranteed such that no test is needed. –  Jan 15 '15 at 03:54
  • Because as I understand if an Object living in a stack it will be freed upon leaving the scope, in a function call after a return statement all stack allocated will be pop. So if you want to access the object for use later it will not be available, CMIIW. But if it use smart pointer such as Automatic reference counting and stored in heap it wont be freed as long as something has reference to it – Marcel Daryanto Jan 19 '15 at 04:08
  • @MarcelDaryanto Not sure what you were trying to say. (1) **Everything** here is on the stack, because you aren't doing _any_ dynamic allocation, so they _must_ be on the stack. (2A) If (optional) NRVO is applied, `felix` gets created in the stack space the caller set aside for `justFelix`, so they are the **same** object; if so, there is actually no local to destroy. (2B) If NRVO is not applied, `felix` is allocated on the stack & copy-assigned to `justFelix`, & `felix` is only destroyed **after** that assignment has completed. In no case are the heap or reference-counting needed or relevant. – underscore_d Aug 03 '16 at 13:26