List and list elements, where are stored?

前端 未结 7 1602
粉色の甜心
粉色の甜心 2021-01-05 17:59

Given this piece of code:

#include 
(void) someFunction(void) {
    list  l;
    l.push_back(1);
}
  • Where are t
相关标签:
7条回答
  • 2021-01-05 18:35

    You could do it this way (as long as I understand your problem)

    #include <iostream>
    #include <list>
    
    using namespace std;
    
    list<int> & fun()
    {
        list<int> & temp = *(new list<int>);
        temp.push_back(4);
        // you can do other operations on the list
        return temp; // you pass the reference, any list will not be destroyed neither copied.
    }
    
    int main()
    {
        list<int> & my_list = fun();
    
        cout << *(my_list.begin()) << endl;
    }
    
    0 讨论(0)
  • 2021-01-05 18:36

    If you changed the function signature to return a list, you could indeed return the list; however the compiler would make a copy of the list, and the copy is the one that would be received by the caller.

    The original list will be destroyed at the end of the function, but the copy will be made before that happens so you will return valid data. If you try to cheat the system and return a pointer or reference instead to avoid the copy, that's when you'll run into undefined behavior.

    The list itself will be on the stack, but the elements contained within will be on the heap. The list will contain pointers that it manages behind the scenes so that you don't have to worry about the storage at all.

    0 讨论(0)
  • 2021-01-05 18:44

    The answer you selected is incorrect about 1 thing...

    returning a list does not call the list's copy constructor.

    list<int> func()
    {
      list<int> res; // &res returns 0x7fff183f0900
      res.push_back(10);
      return res;
    }
    
    list<int> l = func();   // &l also returns 0x7fff183f0900 (no copy)
    

    You can double check this by printing &res in the function and &l outside the function.

    The compiler is optimized to pass through returned objects without making copies, otherwise every single non-pointer object returned would be copied, which would be insane.

    0 讨论(0)
  • 2021-01-05 18:44

    Some of it can vary depending on the whim of the compiler and/or library author.

    As it is right now, there's a pretty fair chance the compiler will detect that the result of creating and populating the list is never used, so it would eliminate the entire function as dead code. To prevent that, you might (for example) return the list instead of just letting it be destroyed at the end of the function.

    That only adds new possibilities though. Most compilers implement Return Value Optimization (RVO) and Named Return Value Optimization (NRVO). These basically mean that when/if you return a value (such as your list object) instead of creating an object on the stack and copying it to the destination when you return it, the compiler generates code to generate the object where it's going to be assigned after return. In this case, instead of creating a local function at all, the function will just receive a hidden pointer to the location where it will write the result.

    A std::list normally allocates space for the data to be stored using std::allocate. You can, however, specify a different allocator for it to use. In this case, the space could be allocated almost anywhere.

    Although it's more common with other (sort of) containers like std::string, it's also possible (in at least some cases) to store at least a small amount of data in the object itself, and only allocate space on the heap when/if that overflows. There are some restrictions on this to maintain exception safety and such, but in the case of list<int> it shouldn't be a problem. For example, the first ten ints might be stored in the list object itself, and only when/if you add more than that, it would allocate space on the heap.

    0 讨论(0)
  • 2021-01-05 18:57

    A return function is declared like this : list<int> somefunc() {list<int> L; return L; } .

    Check that values with list<int>::iterator .

    Like this :

    #include <iostream>
    #include <list>
    using namespace std;
    
    
    list<int> someReturnFunc(int listSize)
    {
        list<int> myList;
    
        for (int g=0; g< listSize; g++)  myList.push_back(g);
    
        return myList;
    }
    
    int main ()
    {
        list<int> yourList;
        list<int>::iterator i;
    
        yourList = someReturnFunc(15);
    
        for(i=yourList.begin(); i != yourList.end(); ++i) cout << *i << " ";
    
        cout << endl;
    
        return 0;
    
    }
    
    0 讨论(0)
  • 2021-01-05 19:02

    Where are the elements of the list stored? Stack? Heap?

    List elements are stored on the heap. You can see this following your debugger down on the push_back method call. The easiest to see it is to store objects rather than POD type, and log the constructor. You'll need a copy constructor as they are get copied. The allocation happens with the template argument allocator, which you can specify or without specifying it it would go with the default heap allocation.

    How can I do to empirically check that values are in stack or heap?

    You can check this with push_back elements from the stack:

    std::list<int> my_list;
    int a = 10;
    my_list.push_back(a);
    a = 11;
    assert(*my_list.begin() == 10);
    

    This function can returns the list?

    In C++ there are two ways to pass data around: by reference or by value. If you're function looks like this,

    list<int> func()
    {
      list<int> res;
      res.push_back(10);
      return res;
    }
    

    then you're passing the list by value, which means that the compiler will call the list's copy constructor which also copies all the values in the list. As the function returns, after it copies the list, the "res" list's destructor will be called, releasing all its elements. However if you do this:

    list<int>& func()
    {
          list<int> res;
          res.push_back(10);
          return res;
    }
    

    You're code will fail as you return the reference to your "res" list, which will be already destroyed at the end of its scope, so you're reference will be invalid.

    The problem with the first solution can be performance. You can also do that without the call of the copy constructor like this:

    void func(list<int>& res)
    {
      res.push_back(10);
    }
    
    list<int> list_to_fill;
    func(list_to_fill);
    

    In this case, there's no copying and it should be faster as there's only one list creation.

    0 讨论(0)
提交回复
热议问题