c++依赖注入:对象生命周期?
我来自 C#,并尝试将我的一些实践转换为 C++。我在整个代码的各个地方使用原始指针使用了依赖注入。然后我决定用 std::shared_ptr 替换原始指针。作为该过程的一部分,建议我考虑使用堆栈分配的自动变量,而不是动态分配它们(请参阅 这个问题虽然这个问题是在 unique_ptr 的上下文中,所以也许是不同的)。
我相信下面的例子展示了自动变量的使用。
class MyClass
{
public:
MyClass(ApplicationService& app): appService_(app)
{
}
~MyClass()
{
appService_.Destroy(something);
}
private:
ApplicationService& appService_;
}
class ConsumerClass
{
DoSomething()
{
CustomApplicationService customAppService;
MyClass myclass(customAppService);
myclass...
}
}
在上面的示例中,当 customAppservice 和 myclass 超出范围时,我如何知道哪个将首先被销毁?如果 customAppService 首先被销毁,则 MyClass 析构函数将失败。在这种情况下,这是使用shared_ptr的好理由吗?还是有一个干净的方法可以解决这个问题?
更新
ApplicationService 是一个类,它是与我的代码使用的第三方库交互所需的全局函数的包装器。我有这个类,因为我相信它是支持单元测试和独立函数的存根/模拟的标准方法。该类只是将调用委托给相应的全局函数。调用 appService_.Destroy(something);实际上是销毁 MyClass 的每个特定实例使用的对象,而不是销毁与 Application 类本身有关的任何内容。
I'm coming from C# and trying to translate some of my practices into C++. I've used dependency injection in various places throughout my code using raw pointers. Then I decide to replace the raw pointers with std::shared_ptr's. As part of that process it was suggested that I consider using stack allocated automatic variables rather than dynamically allocating them (see this question although that question was in the context of unique_ptr so maybe that is different).
I believe the below example shows the use of automatic variables.
class MyClass
{
public:
MyClass(ApplicationService& app): appService_(app)
{
}
~MyClass()
{
appService_.Destroy(something);
}
private:
ApplicationService& appService_;
}
class ConsumerClass
{
DoSomething()
{
CustomApplicationService customAppService;
MyClass myclass(customAppService);
myclass...
}
}
In the above example, when customAppservice and myclass go out of scope how do I know which will be destroyed first? If customAppService is destroyed first than the MyClass destructor will fail. Is this a good reason to use shared_ptr instead in this scenario or is there a clean way around this?
UPDATE
ApplicationService is a class that is a wrapper around global functions needed to interact with a 3rd party library that my code uses. I have this class as I believe it's the standard way to support unit testing and stubbing/mocking of free standing functions. This class simply delegates calls to the corresponding global functions. The call appService_.Destroy(something); is actually destroying an object used by each specific instance of MyClass not destroying anything do with the Application class itself.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
答案是:你不需要知道,因为无论如何你的设计已经被破坏了。
首先,
Destroy
听起来像是一个坏主意,而且如果在一个不负责销毁另一个对象的对象中调用的话。Destroy
方法中的代码属于ApplicationService
的析构函数(希望是虚拟的,尽管在本例中实际上不需要),这与 C# 不同在完全确定的时间点被调用。完成此操作后,您将(希望)意识到,销毁
appService_
不是MyClass
的责任,因为它不拥有它。这是ConsumerClass
(或者更确切地说是DoSomething
方法)的责任,它真正管理实际的服务,并且在您移动后会自动销毁它将
的代码销毁到析构函数中。 RAII 让一切以干净、自动的方式发生,这不是很好吗?恕我直言,这是围绕它的完美干净的 C++ 方法,并且该问题绝对不是垃圾邮件
shared_ptr
的原因。即使您确实需要专用的 Destroy 方法并且无法将代码移动到析构函数中(我将其视为过度思考设计的动机),那么您仍然会调用 Destroy > 再次来自DoSomething
,MyClass 不负责销毁 appService_。编辑:根据你的更新(以及我对
something
论点的愚蠢忽视),你的设计似乎确实相当正确(至少如果你不能乱改变ApplicationService
),抱歉。尽管类成员应该以与构造相反的顺序被销毁,但我不确定这也适用于本地自动变量。为了确保按定义的顺序调用析构函数,您可以做的是使用简单的块引入嵌套作用域:
当然,仍然完全不需要使用动态分配,更不用说
shared_ptr
了。尽管嵌套块对代码造成了一些影响,但这并不能阻止以非动态方式且毫无理由地应用动态分配的丑陋,而且它至少“在语义上看起来不错”customAppService
块顶部的声明;)The answer is: you don't need to know, as your design is broken, anyway.
First, a
Destroy
sounds like a bad idea, furthermore if called in an object that is not responsible for the destruction of the other object. The code from theDestroy
method belongs intoApplicationService
's destructor (which is hopefully virtual, although in this case it doesn't actually need to), which in contrast to C# gets called at a perfectly determined point in time.Once you've done this, you will (hopefully) realize, that it is not the responsibility of
MyClass
to destroy theappService_
, as it does not own it. It is the responsibility of theConsumerClass
(or rather theDoSomething
method), which really manages the actual service and which does actually destroy it automatically once you've movedDestroy
's code into the destructor. Isn't it nice how RAII does make happen everything in a clean and automatic way?This is IMHO the perfect clean C++ way around it and the problem is definitely not a reason to spam
shared_ptr
s. Even if you really need a dedicatedDestroy
method and cannot move the code into the destructor (which I would take as a motivation for overthinking the design), then you would still callDestroy
fromDoSomething
as again, MyClass is not responsible for destroying the appService_.EDIT: According to you update (and my stupid overlooking of the
something
argument), your design seems indeed quite correct (at least if you cannot mess with changing theApplicationService
), sorry.Allthough class members should get destroyed in reverse order of construction, I'm not sure this also holds for local automatic variables. What you could do to make sure the destructors get called in a defined order is introduce nested scopes using simple blocks:
Of course there is still completely no need to use dynamic allocation, let aside
shared_ptr
s. Although the nested blocks blow the code a bit, it is nothing against the ugliness of dynamic allocation applied in a non-dynamic way and without reason and it at least "looks nice in a semantic way" withcustomAppService
's declaration on top of the block ;)在 C++ 中,通常,对象的销毁顺序与其创建顺序完全相反。
根据您的示例,
MyClass
将在CustomApplicationService
之前销毁显式调用析构函数时例外。但是,我认为您现阶段不应该担心此异常。
另一个微妙之处称为 静态初始化顺序失败 。但是,这不适用于自动(堆栈)变量。
编辑:
来自 C++2003 - 寻找“反向顺序”
6.6.0.2
In C++, objects, in general, are destroyed in the order that is exact opposite of the order they were created in.
Based on your example,
MyClass
will be destroyed beforeCustomApplicationService
The exception is when a destructor is called explicitly. However, I don't think you should concern yourself with this exception at this stage.
Another subtlety is called static initialization order fiasco . However, this does not apply to automatic (stack) variables.
Edit:
From C++2003 - looked for 'reverse order'
6.6.0.2