C++-防止全局实例化
C++ - Prevent global instantiation?
有没有办法强制类在堆栈上实例化,或者至少防止它在C++中是全局的?
我想防止全局实例化,因为构造函数调用需要先前初始化的C API。AFAIK没有办法控制全局对象的构造顺序。
编辑:应用程序针对的是一个嵌入式设备,该设备也禁止动态内存分配。用户安装类的唯一可能的解决方案是在堆栈上或通过placement new运算符。
第2版:我的类是一个依赖于其他外部库(来自C API)的库的一部分。我无法修改这些库,也无法控制在最终应用程序中初始化库的方式,这就是为什么我正在寻找一种方法来限制类的使用方式。
与其对类的对象设置一些任意的限制,我更愿意通过将C API的调用封装到一个类中来确保调用的安全性。该类的构造函数将进行初始化,析构函数将释放获取的资源。
然后,您可以要求这个类作为类的参数,初始化总是会成功的。
用于包装的技术被称为RAII,您可以在这个SO问题和这个wiki页面中阅读更多关于它的信息。它最初的目的是将封装资源初始化和发布结合到对象中,但也可以用于各种其他事情。
半个答案:为了防止堆分配(所以只允许堆栈分配),重写操作符new并使其私有。
void* operator new( size_t size );
编辑:其他人说只记录限制,我有点同意,尽管如此,我还是同意:没有堆分配,没有全局分配,API初始化(不完全在构造函数中,但我认为仍然足够好):
class Boogy
{
public:
static Boogy* GetBoogy()
{
// here, we intilialise the APIs before calling
// DoAPIStuffThatRequiresInitialisationFirst()
InitAPIs();
Boogy* ptr = new Boogy();
ptr->DoAPIStuffThatRequiresInitialisationFirst();
return ptr;
}
// a public operator delete, so people can "delete" what we give them
void operator delete( void* ptr )
{
// this function needs to manage marking array objects as allocated
// or not
}
private:
// operator new returns STACK allocated objects.
void* operator new( size_t size )
{
Boogy* ptr = &(m_Memory[0]);
// (this function also needs to manage marking objects as allocated
// or not)
return ptr;
}
void DoAPIStuffThatRequiresInitialisationFirst()
{
// move the stuff that requires initiaisation first
// from the ctor into HERE.
}
// Declare ALL ctors private so no uncontrolled allocation,
// on stack or HEAP, GLOBAL or otherwise,
Boogy(){}
// All Boogys are on the STACK.
static Boogy m_Memory[10];
};
我不知道我是骄傲还是羞愧!:-)
您本身不能阻止将对象作为全局变量。我认为你不应该尝试:毕竟,为什么不能构建一个初始化这些库的对象,全局实例化它,然后全局实例化你的对象?
所以,让我重新表述这个问题,深入到它的核心:
在完成一些初始化工作之前,如何防止构建我的对象?
通常情况下,响应为:取决于。
这一切都归结为初始化工作,特别是:
- 有没有办法检测它还没有被调用
- 多次调用初始化函数有缺点吗
例如,我可以创建以下初始值设定项:
class Initializer {
public:
Initializer() { static bool _ = Init(); (void)_; }
protected:
// boilerplate to prevent slicing
Initializer(Initializer&&) = default;
Initializer(Initializer const&) = default;
Initializer& operator=(Initializer) = default;
private:
static bool Init();
}; // class Initializer
这个类第一次实例化时,它调用Init
,然后忽略它(以微不足道的比较为代价)。现在,从这个类(私下)继承以确保在调用构造函数的初始值设定项列表或主体时,已经执行了所需的初始化,这很简单。
应该如何实现
Init
?
取决于什么是可能的和更便宜的,要么检测初始化已完成,要么调用初始化。
如果C API太糟糕了,你实际上也不能这样做?
你完蛋了。欢迎文档。
您可以尝试使用Singleton模式
有没有办法强制类在堆栈上实例化,或者至少防止它在C++中是全局的?
不是您可以将构造函数设为私有,只使用工厂方法创建所述对象,但没有什么能真正阻止您使用所述方法创建全局变量。
若全局变量是在应用程序进入"main"之前初始化的,那个么您可以在"main"设置一些标志之前从构造函数抛出异常。然而,何时初始化全局变量取决于实现。所以,它们可以在应用程序进入"main"后进行初始化。也就是说,这将依赖于未定义的行为,这不是一个好主意。
理论上,您可以尝试遍历调用堆栈,并从中查看它是被调用的。然而,编译器可以内联构造函数或几个函数,这将是不可移植的,并且在C++中遍历调用堆栈将是痛苦的。
您也可以手动检查"this"指针,并尝试猜测它的位置。然而,这将是特定于该特定编译器、操作系统和体系结构的不可移植的黑客攻击。
所以我想不出什么好的解决办法。
因此,最好的想法是改变你的程序行为,正如其他人已经建议的那样——创建一个单例类,在构造函数中初始化你的C api,在析构函数中解初始化它,并在必要时通过工厂方法请求这个类。这将是解决你的问题最优雅的方法。
或者,您可以尝试记录程序行为。
要在堆栈上分配一个类,只需说
FooClass foo; // NOTE no parenthesis because it'd be parsed
// as a function declaration. It's a famous gotcha.
要在堆上进行分配,您可以说
std::unique_ptr<FooClass> foo(new FooClass()); //or
FooClass* foop = new FooClass(); // less safe
只有在程序范围内声明对象时,对象才会是全局的。
- 从C++实例化QML
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 如何创建一个空的全局类并在启动时实例化它
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 约束和显式模板实例化
- 为什么包含windows.h会产生语法错误,从而阻止类的实例化?(C2146,C2065)
- 对象实例化调用构造函数的次数太多
- 如何使用非默认构造函数实例化模板化类
- 静态数据成员模板专用化的实例化点在哪里
- 错误的cv::face FacemarkLBF实例化
- C++的解析器在可以区分比较和模板实例化之前会做什么?
- 为什么 gcc 和 clang 为函数模板的实例化生成不同的符号名称?
- 从函数中全局删除并重新实例化数组结构,而无需在编译时知道数组的大小
- 实例的全局初始化
- 全局变量的 C++ 后期实例化
- C++-防止全局实例化
- 如何在PHP扩展中实例化全局C++类
- 如何实例化全局智能指针变量
- 全局静态变量实例化行为
- 全局变量的实例化顺序