依赖注入与C ++中的智能指针

时间:2017-09-11 22:44:10

标签: c++ dependency-injection valgrind smart-pointers

我正在尝试在C ++项目中实现依赖注入模式,手动执行注入(无框架)。所以我使用工厂函数手动创建依赖项并将它们传递给使用它们的类。我的问题是,当依赖图的根(本身是由智能指针管理的类实例)超出范围时,其依赖关系(类中引用的智能指针)不会被破坏(valgrind显示丢失的内存块)

我只是看到这样一个基本的例子,其中A类依赖于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?

所以在这个例子中我使用A_Factory::getInstance得到A,所以无论使用什么A都不知道A是如何创建的,A也不知道它的依赖是如何创建的。而且我的理解是,使用智能指针时,他们会在超出范围时自动删除,希望在根超出范围后链接依赖关系图。如果我必须实现代码来销毁依赖项,那么我从智能指针中得不到多少好处。

所以我不知道我是不是用智能指针设置正确的东西,或者valgrind并没有告诉我我认为它意味着什么。我对valgrind的理解是,它实际上只指出 my code 范围内的问题,所以如果标准库正在删除依赖项,那么valgrind可能无法反映出来。然而,当我使用围绕一个普通类(没有依赖项)的智能指针对一个简单的程序运行valgrind时,它不会显示任何丢失的内存。

我还会注意到,我在stackoverflow上看到的一些例子对我没用,比如不在A的初始化列表中调用std::move。而且我想避免传递任何原始指针。

2 个答案:

答案 0 :(得分:0)

我正在使用不包含make_unique的g ++ 4.8.5但是我添加了Herb Sutter的建议make_unique implementation并在valgrind下运行测试,显示没有泄漏。

#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();
}

也许你的问题源于你正在使用的编译器中的make_unique实现?

答案 1 :(得分:0)

我在所有构造函数和析构函数中使用print语句对代码进行了检测。此外,我已禁用所有编译器生成的构造函数,以确保它们不运行:

#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
}

这个程序为我输出:

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

我正在为每个析构函数计算一个构造函数。你对编译器有同样的看法吗?如果是这样,一切都很好。