如何在C++中实现初始化终结器
How to implement initialization finalizers in C++?
我想在基类中实现初始化终结器。最简单的方法是为方法提供最终确定过程。不幸的是,它迫使我们记住总是在最派生的构造函数末尾调用它——这对客户端来说非常糟糕。我认为我可以在基类中使用RAII来达到理想的效果,并编写了这样的代码:
#include <iostream>
using namespace std;
struct Base
{
Base()
{
struct Finishializer
{
~Finishializer()
{
cout << "Base::~Finishializer" << endl;
}
} finishializer;
cout << "Base::Base()" << endl;
}
~Base()
{
cout << "Base::~Base()" << endl;
}
};
struct Derived : Base
{
Derived()
{
cout << "Derived::Derived()" << endl;
}
~Derived()
{
cout << "Derived::~Derived()" << endl;
}
};
int main()
{
Derived();
}
然后我意识到构造函数的调用堆栈求值顺序相反。我的"Finishializer模式"要求首先调用基构造函数,然后在基构造函数的末尾调用派生构造函数(作为下一个堆栈帧)。
不幸的是,C++(在我的例子中是VS2015)以另一种方式工作:它调用派生构造函数,但作为第一条指令,它调用基构造函数(作为下一个堆栈帧)。
它导致以下输出:
Base::Base()
Base::~Finishializer
Derived::Derived()
Derived::~Derived()
Base::~Base()
而不是我梦想中的
Base::Base()
Derived::Derived()
Base::~Finishializer
Derived::~Derived()
Base::~Base()
是否有充分的理由按原样评估堆栈,或者可以按照我的建议对其进行更改以实现"finishializers"?你知道用当前的C++实现来做这些事情的一些替代模式吗?
我还没有找到一种方法来使用基类中的某些东西来完成您想要做的事情。我发现唯一有效的方法是在最派生类的构造函数中添加代码。在您的情况下,
Derived::Derived()
{
cout << "Derived::Derived()" << endl;
Finishializer();
}
一旦您决定从Derived
派生并希望在新派生的类中练习Finishializer();
的代码,这将是一个令人头疼的维护问题。再一次,我还没有遇到一种设计/实现模式,如果不在最派生的类中显式地添加代码,它就可以工作。
下面的第一种方法,使用工厂函数,有点脏,但我认为它可以满足您的要求。
另一种更愚蠢的方法是要求对具体的、可用的类进行特殊的最终类派生。例如,在Microsoft的ATL库中使用了这种方法,但没有强制执行。但让我们先做工厂:
#include <iostream>
#include <memory> // std::unique_ptr
#include <type_traits> // std::is_base_of
#include <utility> // std::(forward)
using namespace std;
void say( char const* const s ) { cout << s << "n"; }
#define STATIC_ASSERT( e ) static_assert( e, "`" #e "` <-- must hold." )
template< class Base, class Derived >
using Is_base_and_derived = is_base_of<Base, Derived>; // (sic!).
class Base
{
friend class Base_factory;
private:
void finalize_construction() { say( "Finalizing construction." ); }
protected:
virtual ~Base() { say( "Base::<destroy>" ); }
Base() { say( "Base::<init>" ); }
};
class Derived:
public Base
{
friend class Base_factory;
protected:
~Derived() override { say( "Derived::<destroy>" ); }
Derived() { say( "Derived::<init>" ); }
};
class Base_factory
{
private:
static void destroy( Base const* const p )
{ delete p; }
public:
template< class Class >
using Ptr_ = unique_ptr<Class, void(*)(Base const*)>;
template< class Class, class... Args >
static auto make_a( Args&&... args )
-> Ptr_<Class>
{
STATIC_ASSERT(( Is_base_and_derived<Base, Class>::value ));
auto result = Ptr_<Class>{
new Class{ forward<Args>( args )... }, &destroy
};
result->finalize_construction();
return result;
}
};
auto main()
-> int
{
(void) Base_factory::make_a<Derived>();
}
强制派生类方法避免了上面代码中的动态分配,并且避免了对客户端代码一致性的依赖:
#include <assert.h> // assert
#include <iostream>
#include <memory> // std::unique_ptr
#include <type_traits> // std::is_base_of
#include <utility> // std::(forward)
using namespace std;
void say( char const* const s ) { cout << s << "n"; }
#define STATIC_ASSERT( e ) static_assert( e, "`" #e "` <-- must hold." )
//------------------------------------------- Machinery:
class With_enforced_most_derived;
template< class Some_class, class The_virtual_top = With_enforced_most_derived>
class Construction_finalizer_ final
: public Some_class
, public virtual The_virtual_top
{
public:
template< class... Args >
Construction_finalizer_( Args&&... args )
: The_virtual_top{ typename The_virtual_top::Key{} }
, Some_class{ forward<Args>( args )... }
{ say( "Finalizing construction." ); }
};
class With_enforced_most_derived
{
template< class, class > friend class Construction_finalizer_;
private:
enum Key{};
public:
With_enforced_most_derived() // Needed for intermediate classes.
{ assert( "Most derived class must be `Construction_finalizer_`" && 0 ); }
With_enforced_most_derived( Key )
{}
};
//------------------------------------------- Example usage:
class Base
: public virtual With_enforced_most_derived
{
public:
virtual ~Base() { say( "Base::<destroy>" ); }
Base() { say( "Base::<init>" ); }
};
class Derived:
public Base
{
public:
~Derived() override { say( "Derived::<destroy>" ); }
Derived() { say( "Derived::<init>" ); }
};
auto main()
-> int
{
#ifdef CRASH_BABY_CRASH
(void) Derived{};
#endif
(void) Construction_finalizer_<Derived>{};
}
相关文章:
- 如何实现使用 gcc-4.4 编译的大向量初始化?
- 在声明或实现中延迟初始化C++单一实例
- 为什么make_tuple的实现不会通过大括号初始化返回?
- 生产者消费者实现中的条件变量应如何初始化
- 如何在C++中实现初始化终结器
- 在某些情况下,如何理解允许实现将非局部变量的动态初始化视为静态初始化
- 如何实现便捷的初始化?
- 逗号分隔的初始化(如Eigen中的初始化)如何可能在C++中实现
- 我是否必须在函数的声明和实现中编写初始化列表
- c2797 成员初始值设定项列表或非静态数据成员初始值设定项中的列表初始化未实现
- C++编译器在 main 之后实现动态初始化
- 使用纯虚拟函数的实现初始化
- 抱歉,未实现:c++ 11中的非静态数据成员初始化器
- 尝试为特征矩阵实现一种初始化列表语法
- 如何初始化实现文件中的静态常量集<string>?
- 在c++中映射初始化以实现尝试
- 定义了静态初始化实现的顺序
- 如何实现RAII +延迟初始化
- 在C++中实现全局变量和静态成员变量的动态初始化
- 如何使用资源获取初始化实现构建器模式