3

I'm an Objective-C programmer, and am recently starting C++, and I've stumbled into this question on my code's organization:

std::list<char *> stuff = std::list<char *>();
thing *object = new thing(stuff);

Where stuff would be an object that I'd need for the lifetime of my class (that is, until it gets destructed), how to avoid losing it?

On Objective-C, I could simply call -retain on the constructor. On C++?

Matoe
  • 2,742
  • 6
  • 33
  • 52
  • 2
    If `stuff` is supposed to live exactly as long as `object` it maybe that it should be in object and just let RAII take care of its lifetime. Oh ps, `new anthing` is almost always evil so be careful – daniel gratzer Dec 25 '12 at 00:34
  • 1
    `thing` will not be destroyed until you explicitly `delete` it. I would recommend getting a good [C++ book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) to learn the basics. – David Brown Dec 25 '12 at 00:40
  • how would you have `stuff` to fade out of existance? do you mean you're creating this inside a function? – Rubens Dec 25 '12 at 00:44
  • If 'stuff' is scoped to a narrower scope than the intended lifetime of 'object', you'll have a dangling pointer unless your 'thing' class copies the string pointed to by 'stuff'. Is overcoming that problem your question? – DavidO Dec 25 '12 at 00:46

3 Answers3

7

Do not use pointers when you don't need them, and don't use owning raw pointers (unless you have a very good reason for them).

Use automatic storage duration:

std::list<char> stuff;
thing object{stuff};

The constructor of thing would take std::list<char> as its argument:

#include <utility> // for std::move

class thing {
public:
    explicit thing(std::list<char> stuff_) : stuff(std::move(stuff_)) {}

private:
    std::list<char> stuff;
};

If you do it this way, the destructor of thing will be called when thing goes out of scope, implicitly calling the destructor of stuff. Many good C++ books explain this in great detail.

Unlike Objective-C, and C++ uses RAII rather than reference counting. The basic rule is: use automatic storage duration when possible, avoid raw owning pointers, and don't use new unless you have a good reason for it.

Community
  • 1
  • 1
  • It's worth mentioning that this will only compile with a C++11 compiler, on GCC you'll need to use `g++ -std=c++0x` – daniel gratzer Dec 25 '12 at 00:48
  • Or if others needed access to the same list, to pass by reference and have the thing class take a reference to the list instead of moving it. As is, there isn't a point to moving a newly constructed object. – Ryan Guthrie Dec 25 '12 at 03:34
1

The usual way would be to copy or move stuff into thing in the constructor of thing:

class thing {
public:
    thing(std::list<char*> stuff) : stuff(std::move(stuff)) {}
private:
    std::list<char *> stuff;
};
Mankarse
  • 39,818
  • 11
  • 97
  • 141
1

It's not clear how you are going to use stuff in your example, so I'm going to give you a few different options.

  1. thing stores its own copy of stuff.
    In this case your class stores an object of type std::list<char*>.

    class thing
    {
    public:
      thing(std::list<char*>& aList):m_list(alist){}
      std::list<char*> m_list;
    };
    

    When you construct thing copy of stuff is made and stored in the class. When the object is destructed it will automatically deallocate m_list.

  2. thing stores a weak reference to stuff.
    Your class will store a pointer (std::list<char*>* m_list) or reference (std::list<char*>& m_list). thing will be able to use your list in any way, but it shouldn't be in charge of resource management. If the list is in a smaller scope than thing then you'll be left with a hanging reference.

    thing getThing()
    {
    std::list<char*> list1;
    thing object1(list1);
    return object1; //bad - list will be deallocated, object1 will have a hanging reference
    }
    
  3. thing stores a shared pointer to stuff. This is the method that is most like retain in Objective C. C++ doesn't have automatic reference counting. If you want to store an object reference with shared ownership you can use an std::shared_ptr. thing stores std::shared_ptr<std::list<char*>> m_list.

    std::shared_ptr<std::list<char*>> stuff = std::make_shared<std::list<char*>>();
    thing object(stuff); //reference count incremented, even if stuff is destroyed object will still hold a valid reference
    
Elliot Hatch
  • 1,038
  • 1
  • 12
  • 26