[英]Is there any Dynamic Binding During Deinitialization idiom
Aka: Is there any "Calling Virtuals During Deinitialization" idiom Aka:是否有“在初始化期间调用虚拟机”的成语
I am cleaning up some old code and need to fix cases where virtual methods are called in constructors and destructors. 我正在清理一些旧代码,需要修复在构造函数和析构函数中调用虚拟方法的情况。 I don't know the code base and it is huge. 我不知道代码库,它很大。 Major rewrite is not an option. 不能进行重大重写。
The fix for constructors was simple. 构造函数的修复很简单。 I moved the virtual calls to a static Create
template and made all the constructors protected. 我将虚拟调用移至静态的Create
模板,并保护了所有构造函数。 Then all I needed to do was to compile and change all location causing errors to use the Create
template. 然后,我要做的就是编译并更改所有位置,从而导致使用Create
模板时出错。 Minimal chance for regressions. 回归的机会最小。 However there is no analog to this for destructors. 但是,对于析构函数,没有类似的方法。
How would you solve this? 您将如何解决?
Example code 范例程式码
#include <iostream>
class Base
{
public:
virtual ~Base()
{
DeInit();
}
protected:
virtual void DeInit()
{
std::cout << "Base" << std::endl;
}
};
class Derived : public Base
{
protected:
virtual void DeInit() override
{
std::cout << "Derived" << std::endl;
Base::DeInit();
}
};
int main()
{
Derived d;
}
This code does not call Derived::DeInit
(only prints "Base"). 此代码不调用Derived::DeInit
(仅打印“ Base”)。 I need to fix this kind of issues. 我需要解决此类问题。
...
virtual Base::~Base()
{
Base::DeInit();
}
...
...
Derived::~Derived()
{
// de-initialization code
// do not call Derived::DeInit() here as otherwise Base::DeInit()
// will be called two times
}
...
and cleanup of virtual function calls from destructors when spotting them. 并在发现析构函数时从析构函数中清除虚函数调用。
This is quite tricky, as destructors are called automatically on leaving scopes, whether by normal flow, break
, continue
, return
or throw
. 这很棘手,因为析构函数会在离开范围时自动调用,无论是通过正常流程, break
, continue
, return
还是throw
。 That's also why you can't pass arguments to a destructor. 这就是为什么您不能将参数传递给析构函数的原因。
The straightforward solution is to call Derived::DeInit
from Derived::~Derived
. 直接的解决方案是从Derived::~Derived
Derived::DeInit
调用Derived::DeInit
。 This has the additional benefit of still having Derived
members available. 这还有使Derived
成员可用的额外好处。
Another is to create your own smart pointer class, which calls T::DeInit
before T::~T
. 另一个方法是创建自己的智能指针类, T::DeInit
在T::~T
T::DeInit
之前调用T::DeInit
。 To prevent this from being bypassed, return this smart pointer from your Create
. 为避免被绕过,请从Create
返回此智能指针。
you dont need to have a virtual DeInit fun. 您不需要虚拟的DeInit乐趣。
#include <iostream>
class Base
{
public:
virtual ~Base()
{
DeInit(); //this calls Base version
}
protected:
void DeInit()
{
std::cout << "Base" << std::endl;
}
};
class Derived : public Base
{
public:
~Derived()
{
DeInit(); //this calls Derived version
}
protected:
void DeInit()
{
std::cout << "Derived" << std::endl;
}
};
int main()
{
Derived d;
}
Output: Derived Base 输出:衍生基数
is this what you wanted? 这就是你想要的吗?
A solution inspired by MSalters second idea. 受MSalters第二个想法启发的解决方案。
This solution only requires changes to Base
class and to instantiation of Derived
classes. 此解决方案仅需要更改Base
类和Derived
类的实例。 No changes needed to any Derived
implementation. 无需对任何Derived
实施进行任何更改。
#include <iostream>
#include <memory>
class Base
{
private:
template <class T>
class WithAutoDeInit : public T
{
public:
virtual ~WithAutoDeInit() override
{
T::DeInit();
}
};
public:
template <class T>
static std::unique_ptr<typename std::enable_if<std::is_base_of<Base, T>::value, WithAutoDeInit<T>>::type> Create()
{
return std::make_unique<WithAutoDeInit<T>>();
}
virtual ~Base() = default;
protected:
virtual void DeInit()
{
std::cout << "Base" << std::endl;
}
};
class Derived : public Base
{
protected:
virtual void DeInit() override
{
std::cout << "Derived" << std::endl;
Base::DeInit();
}
};
int main()
{
Base::Create<Derived>();
}
This is not a robust solution. 这不是一个可靠的解决方案。 You can still make instances of Derived
directly. 您仍然可以直接制作“ Derived
实例。 And if you update all your Derived
classes with protected constructors an unknowing developer could still create a new class forgetting to make its constructors protected. 而且,如果您使用受保护的构造函数更新所有Derived
类,那么一个不知情的开发人员仍然会创建一个新类,而忘记使其构造函数受到保护。 I wonder if this could be enforced by some kind of assert in a strategic location? 我想知道这是否可以通过战略位置中的某种主张来实施?
static_assert(std::is_constructible<Derived>::value, "Derived class is constructable");
Btw: I finally choose to rewite the code. 顺便说一句:我终于选择重新编写代码。 It is managable I think, and the resulting code will off cause be simpler (hence better). 我认为这是可管理的,并且生成的代码会更简单(因此更好)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.