C++;自我注册的课程有多安全? 从我在C++中实现了类似的系统到所选择的解决方案。 我的问题是,用户D·詹姆斯在这里声明,这个解决方案可能不适用于每个编译器(我现在使用GCC),并且没有在C++标准中定义。
假设我有一个用于接口的抽象基类和一个作为单例的工厂类,该工厂类存储指向一个函数的指针,该函数构造从该接口派生的特定类 然后我有一个助手类,大致如下所示: base.hpp 以及(通过宏)创建此类对象以注册自身的实现: impl1.cppC++;自我注册的课程有多安全? 从我在C++中实现了类似的系统到所选择的解决方案。 我的问题是,用户D·詹姆斯在这里声明,这个解决方案可能不适用于每个编译器(我现在使用GCC),并且没有在C++标准中定义。,c++,class,gcc,standards-compliance,C++,Class,Gcc,Standards Compliance,假设我有一个用于接口的抽象基类和一个作为单例的工厂类,该工厂类存储指向一个函数的指针,该函数构造从该接口派生的特定类 然后我有一个助手类,大致如下所示: base.hpp 以及(通过宏)创建此类对象以注册自身的实现: impl1.cpp 如何兼容C++标准是这个解决方案?假设类实例化ind impl1.cpp甚至会发生,因为主程序中没有任何东西会在编译时显式调用它,这样安全吗 提前感谢您的回答。从标准的角度来看,您可以确定该翻译单元是否包含在构建中。然而,随着旧的,Visual C++静态库存在
如何兼容C++标准是这个解决方案?假设类实例化ind impl1.cpp甚至会发生,因为主程序中没有任何东西会在编译时显式调用它,这样安全吗
提前感谢您的回答。从标准的角度来看,您可以确定该翻译单元是否包含在构建中。然而,随着旧的,Visual C++静态库存在问题。为了安全起见,我会在控制的顶层使用显式模块初始化,或者使用原始iostreams实现所采用的技巧,其中头文件会导致初始化一个小的内部链接,如果尚未初始化,则会导致模块初始化
哦,我有一个问题:有没有人记得“霍尔信封”模块初始化功能,或者告诉我一些材料?我记得几年前重新搜索过,只提到了我自己以前的问题。令人沮丧。不,通常不能保证可值的
impl1
会被初始化。该标准规定,在调用同一翻译单元(同一.cpp
文件)中定义的第一个函数之前,或在首次使用该翻译单元中的变量之前,必须初始化名称空间范围变量
法律的字母是C++11[basic.start.init]§4
:
具有静态存储持续时间的非局部变量的动态初始化是否在main
的第一条语句之前完成是由实现定义的。如果初始化延迟到main
的第一条语句之后的某个时间点,则应在首次odr使用(3.2)与待初始化变量定义在同一转换单元中的任何函数或变量之前进行
因此,如果您的
impl1.cpp
仅包含注册变量,则不能保证它们会被初始化。但是,如果它包含在程序运行时执行的任何函数(或从外部引用的变量),则保证在运行任何此类函数或引用变量之前对其进行初始化。我发现代码存在两个问题。首先,您使用的是动态分配,其次,您使用的是函数指针。以下是我的解决方案:-
#include <iostream>
#include <string>
#include <map>
class FactoryBase
{
protected:
FactoryBase (const std::string &name)
{
m_factory_items [name] = this;
}
public:
virtual ~FactoryBase ()
{
}
template <class T> static T *Create ()
{
return static_cast <T *> (m_factory_items [T::Name]->Create ());
}
private:
virtual void *Create () = 0;
private:
static std::map <const std::string, FactoryBase *>
m_factory_items;
};
std::map <const std::string, FactoryBase *>
FactoryBase::m_factory_items;
template <class T>
class FactoryItem : public FactoryBase
{
public:
FactoryItem () :
FactoryBase (T::Name)
{
std::cout << "Registering class: " << T::Name << std::endl;
}
virtual ~FactoryItem ()
{
}
private:
virtual void *Create ()
{
return new T;
}
};
class A
{
public:
A ()
{
std::cout << "Creating A" << std::endl;
}
virtual ~A ()
{
std::cout << "Deleting A" << std::endl;
}
static const std::string
Name;
private:
static FactoryItem <A>
m_registration;
};
const std::string
A::Name ("A");
FactoryItem <A>
A::m_registration;
class B
{
public:
B ()
{
std::cout << "Creating B" << std::endl;
}
virtual ~B ()
{
std::cout << "Deleting B" << std::endl;
}
static const std::string
Name;
private:
static FactoryItem <B>
m_registration;
};
const std::string
B::Name ("B");
FactoryItem <B>
B::m_registration;
int main (int argc, char *argv [])
{
A
*item_a = FactoryBase::Create <A> ();
B
*item_b = FactoryBase::Create <B> ();
delete item_a;
delete item_b;
}
#包括
#包括
#包括
类FactoryBase
{
受保护的:
FactoryBase(常量标准::字符串和名称)
{
m_工厂_项目[名称]=此;
}
公众:
虚拟~FactoryBase()
{
}
模板静态T*创建()
{
返回static_cast(m_factory_items[T::Name]->Create());
}
私人:
虚空*Create()=0;
私人:
静态std::map
m_工厂_项目;
};
标准::地图
FactoryBase::m_工厂_项目;
模板
类FactoryItem:公共FactoryBase
{
公众:
FactoryItem():
FactoryBase(T::Name)
{
std::cout因此,在Angew之前指向我的位置进一步查看标准后,我注意到标准的[basic.start.init]§4中的脚注34
,其中说明:
即使未使用odr(3.2、3.7.1),也必须初始化具有静态存储持续时间且具有初始化副作用的非局部变量。
这实际上解决了这里提到的问题,自注册类没有使用odr,并且修改了工厂对象的状态,因此具有副作用的初始化
因此,根据这个脚注,像我和Skizz提到的那样进行自我注册实际上是安全的
编辑:正如Matt McNabb提到的,我不应该依赖脚注。因此,下面是脚注所指的规范部分:[Basic.stc.static]§2
如果具有静态存储持续时间的变量具有初始化或具有副作用的析构函数,则即使该变量看起来未使用,也不得将其删除,除非类对象或其副本/移动可以按照12.8中的规定删除。
是解决此特定问题的此工厂模式的实现
它确保factory singleton实现是在构造时调用注册器方法的实现。这意味着,如果使用factory,注册将发生。此时,不幸的是,问题可能不是代码的标准化,而是实现的优化功能。您需要确保e您的编译器没有优化掉您在其他地方不使用的那些注册变量。这在场景中对我有一次影响。因此
与.a
场景相比。@Plasmah实现不允许删除属于程序一部分的任何对象。您如何指定程序的一部分取决于实现,但是库的定义传统上意味着,其中的目标文件只有在解析未定义的外部时才成为程序的一部分;这不是优化,而是库的工作方式。(和FWIW:a.dll
或a.so...
implRegistrator* impl1 = new implRegistrator(getConstructPointer());
#include <iostream>
#include <string>
#include <map>
class FactoryBase
{
protected:
FactoryBase (const std::string &name)
{
m_factory_items [name] = this;
}
public:
virtual ~FactoryBase ()
{
}
template <class T> static T *Create ()
{
return static_cast <T *> (m_factory_items [T::Name]->Create ());
}
private:
virtual void *Create () = 0;
private:
static std::map <const std::string, FactoryBase *>
m_factory_items;
};
std::map <const std::string, FactoryBase *>
FactoryBase::m_factory_items;
template <class T>
class FactoryItem : public FactoryBase
{
public:
FactoryItem () :
FactoryBase (T::Name)
{
std::cout << "Registering class: " << T::Name << std::endl;
}
virtual ~FactoryItem ()
{
}
private:
virtual void *Create ()
{
return new T;
}
};
class A
{
public:
A ()
{
std::cout << "Creating A" << std::endl;
}
virtual ~A ()
{
std::cout << "Deleting A" << std::endl;
}
static const std::string
Name;
private:
static FactoryItem <A>
m_registration;
};
const std::string
A::Name ("A");
FactoryItem <A>
A::m_registration;
class B
{
public:
B ()
{
std::cout << "Creating B" << std::endl;
}
virtual ~B ()
{
std::cout << "Deleting B" << std::endl;
}
static const std::string
Name;
private:
static FactoryItem <B>
m_registration;
};
const std::string
B::Name ("B");
FactoryItem <B>
B::m_registration;
int main (int argc, char *argv [])
{
A
*item_a = FactoryBase::Create <A> ();
B
*item_b = FactoryBase::Create <B> ();
delete item_a;
delete item_b;
}