Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [solved] RAII and object ownership  (Read 2275 times)

0 Members and 2 Guests are viewing this topic.

foobarbaz

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
[solved] RAII and object ownership
« on: February 04, 2014, 10:40:33 pm »
I've been trying to grasp RAII, and understand that all resources should be wrapped in an object. When the object is constructed, the resource is initialized. When the object goes out of scope, the resource is deinitialized. I hope my understanding is correct. I know many of you are sticklers for RAII.

Free store memory is a resource, and thus it has to be wrapped in an object. This is a smart pointer, which ensures the memory is released when the owner smart pointer object goes out of scope. This makes a lot of extra ugly typing everywhere.

So my question is this: Can I use a bare new operator to pass a new object to a manager class that will act as it's owner? Would that acceptably follow RAII?

What I want:

class Foo
{
    public:
        virtual void dog() = 0;
};

class FooBazz : public Foo
{
    public:
        void dog(){}
};

class FooManager
{
    public:
        void addFoo(Foo* foo)
        {
            mFoos.push_back(std::move(std::unique_ptr<Foo*>(foo)));
        }

    private:
        std::vector<std::unique_ptr<Foo>> mFoos;
};

void initStuff(FooManager& fooMgr)
{
    fooMgr.addFoo(new FooBazz);
}
 

What I'm trying to avoid:

void initStuff(FooManager& fooMgr)
{
    std::unique_ptr<Foo> foo(new FooBazz);
    fooMgr.addFoo(foo);
}
 

My justification for the former is that you can imply that fooMgr assumes ownership of the object since it is not wrapped in a smart pointer. This is analogous to the way you can pass raw pointers as parameters into functions knowing the function is not responsible for the pointer (I've seen this done in RAII code). Also, if I as a forgetful programmer forget to assume ownership of the Foo object, my program will have bugs regardless of whether or not I wrapped it in a std::unique_ptr in initStuff(). A smart pointer would go out of scope, and the FooBazz I passed would be invalid memory later in the program. Without a smart pointer, it'd be a memory leak.

What do you guys think?
« Last Edit: February 05, 2014, 12:01:31 am by tedsta »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: RAII and object ownership
« Reply #1 on: February 04, 2014, 11:36:06 pm »
I know many of you are sticklers for RAII.
I'm probably the worst of them, especially after my article ;D

So my question is this: Can I use a bare new operator to pass a new object to a manager class that will act as it's owner? Would that acceptably follow RAII?
I would avoid it when possible, since it adds an additional source of error, even if small. Such cases can quickly become dangerous with respect to exception safety, especially if multiple new calls are involved.

What you should try instead is to use the factory functions as much as possible, e.g. std::make_unique() in C++14.
fooMgr.addFoo(std::make_unique<FooBazz>());

One possibility is also to use the emplacement idiom combined with perfect forwarding (I hope I got the syntax right):
template <typename... Args>
void addFoo(Args&&... args)
{
    mFoos.emplace_back(std::forward<Args>(args)...);
}

fooMgr.addFoo<FooBazz>();

But don't overuse that. As you can see, it requires a decent amount of non-straightforward code, and it forces you to write the implementation in the header, which can lead to dependency bottlenecks.
« Last Edit: February 04, 2014, 11:39:05 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

foobarbaz

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: RAII and object ownership
« Reply #2 on: February 05, 2014, 12:01:07 am »
I know many of you are sticklers for RAII.
I'm probably the worst of them, especially after my article ;D

I was hoping you'd respond to this, and that was actually one of the first articles I read on RAII :P

What you should try instead is to use the factory functions as much as possible, e.g. std::make_unique() in C++14.
fooMgr.addFoo(std::make_unique<FooBazz>());

One possibility is also to use the emplacement idiom combined with perfect forwarding (I hope I got the syntax right):
template <typename... Args>
void addFoo(Args&&... args)
{
    mFoos.emplace_back(std::forward<Args>(args)...);
}

fooMgr.addFoo<FooBazz>();

Wow, thanks for that! :D This fixes so many things. I can see that the implementation of std::make_unique uses the template magic in your emplacement example. Since C++14 isn't available to me yet, I'll make a little make_unique while I wait for Codeblocks to have a C++14 flag. I'm far too lazy to set up codeblocks with the new gcc on all my machines ;) This is about the time I wish I was more of a linux junkie who likes to write C++ code in VIM and compile on the command line.

But anyway, thanks Nexus, your reply solves soooo much smelly code I have in my project.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: RAII and object ownership
« Reply #3 on: February 05, 2014, 12:10:18 am »
Since C++14 isn't available to me yet, I'll make a little make_unique while I wait for Codeblocks to have a C++14 flag.
Or just use aurora::makeUnique(). The library is very easy to use (no installation required) and contains some handy features :)
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development: