简体   繁体   中英

Dependency injection w/ smart pointers in C++

I'm trying to implement the dependency injection pattern in a C++ project, performing injection manually (no framework). So I'm using a factory function to manually create the dependencies and pass them into the classes that use them. My problem is that when the root of the dependency graph (itself a class instance managed by a smart pointer) goes out of scope, its dependencies (smart pointers referenced within the class) don't get destroyed (valgrind shows lost blocks of memory).

I'm seeing this with just a basic example like this, where class A depends on class B:

class B{
public:
    B() {}
    ~B() {}
};

class A{

    std::unique_ptr<B> b_;

public:

    A(std::unique_ptr<B> b) : b_(std::move(b)) { }
    ~A(){}
};

namespace A_Factory {
    std::unique_ptr<A> getInstance(){
        return std::make_unique<A>(std::make_unique<B>());
    }
}

int main(void){
    auto a = A_Factory::getInstance();
    //do some A stuff
} //a goes out of scope and gets deleted?

So in this example I use A_Factory::getInstance to get A, so whatever is using A doesn't know about how A is created, nor does A know how its dependency is created. And it was my understanding that with smart pointers they'd automatically delete when going out of scope, which hopefully would chain down the dependency graph once the root goes out of scope . If I had to implement code to destroy the dependencies then I'm not getting much benefit from the smart pointer.

So I can't tell if I'm not setting up things right with the smart pointers, or perhaps valgrind isn't telling me what I think it means. My understanding with valgrind is that it's really only pointing out issues within the scope of my code , so if the standard library is deleting dependencies then valgrind may not reflect that. However when I run valgrind against a simple program using a smart pointer wrapped around a trivial class (no dependencies) it doesn't show any lost memory.

I'll also note that some examples I've seen here on stackoverflow have no worked for me, like not calling std::move in A's initialization list. And I'd like to avoid any raw pointers being passed around.

I'm using g++ 4.8.5 which doesn't include make_unique but I've added Herb Sutter's suggested make_unique implementation and run your test under valgrind which shows no leaking.

#include <iostream>
#include <cstdlib>
#include <memory>

using namespace std;

template<typename T, typename ...Args>
std::unique_ptr<T> make_unique(Args&& ...args)
{
   return std::unique_ptr<T>(new T ( std::forward<Args>(args)...));
}

class B{
public:
    B() {}
    ~B() {}
};

class A{

    std::unique_ptr<B> b_;

public:

    A(std::unique_ptr<B> b) : b_(std::move(b)) { }
    ~A(){}
};

namespace A_Factory {
    std::unique_ptr<A> getInstance(){
        return make_unique<A>(make_unique<B>());
    }
}

int main(void){
   auto a = A_Factory::getInstance();
}

Perhaps your problem stems from the make_unique implementation in whatever compiler you're using?

I've instrumented your code with print statements in all constructors, and in the destructors. Furthermore I've disabled all compiler-generated constructors to make sure they don't run:

#include <iostream>
#include <memory>

class B{
public:
    B() {std::cout << "B()\n";}
    ~B() {std::cout << "~B()\n";}
    B(const B&) = delete;
};

class A{

    std::unique_ptr<B> b_;

public:

    A(std::unique_ptr<B> b) : b_(std::move(b)) {std::cout << "A()\n";}
    ~A(){std::cout << "~A()\n";}
    A(const A&) = delete;
};

namespace A_Factory {
    std::unique_ptr<A> getInstance(){
        return std::make_unique<A>(std::make_unique<B>());
    }
}

int main(void){
    auto a = A_Factory::getInstance();
    //do some A stuff
}

This program outputs for me:

B()
A()
~A()
~B()

I'm counting one constructor for each destructor. Do you see the same thing with your compiler? If so, all is well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM