std::set 用作静态模板化成员变量
std::set used as a static templated member variable
我正在尝试制作类似Java风格的Enum的东西,我称之为标志。要求是每个标志都是静态的,因此标志是可直接引用的,每个标志存储其名称的字符串和整个集合可迭代并有利于查找。
我正在使用模板,以便每组标志都单独存储(从而使我不必在每个子类中显式放置一组标志)。
我确信这是一个启动问题,因为运行程序的成功或失败取决于包含标志声明的对象文件的文件名(A.o 段错误,但 Z.o 运行良好。
问题似乎是静态初始化顺序之一,这段代码编译得很好,但是当它运行时,gdb 会产生以下内容:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff751e0fa in std::_Rb_tree_decrement(std::_Rb_tree_node_base*) ()
from /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/libstdc++.so.6
(gdb) bt
#0 0x00007ffff751e0fa in std::_Rb_tree_decrement(std::_Rb_tree_node_base*) ()
from /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/libstdc++.so.6
#1 0x0000000000462669 in operator-- ()
at /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/bits/stl_tree.h:199
#2 _M_insert_unique ()
at /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/bits/stl_tree.h:1179
#3 insert () at /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/bits/stl_set.h:411
#4 Flag () at include/../util/include/Flag.hpp:34
#5 ItemFlag () at include/Item.hpp:22
#6 __static_initialization_and_destruction_0 () at Item.cpp:15
#7 global constructors keyed to _ZN3code8ItemFlag5brickE() () at Item.cpp:86
#8 0x000000000046ac62 in ?? ()
#9 0x00007fffffffddc0 in ?? ()
#10 0x000000000046abb0 in ?? ()
#11 0x0000000000692c0a in ?? ()
#12 0x0000000000407693 in _init ()
#13 0x00007ffff7dded08 in ?? () from /usr/lib64/libboost_serialization-1_42.so.1.42.0
#14 0x000000000046abe7 in __libc_csu_init ()
#15 0x00007ffff6cd9b50 in __libc_start_main () from /lib64/libc.so.6
#16 0x0000000000408329 in _start ()
我的代码如下:
template <class FlagType> class Flag
{
public:
Flag(int ordinal, String name):
ordinal(ordinal),
name(name)
{
flagSet.insert(this);
}
inline bool operator==(const Flag<FlagType>& e) const
{
//edited due to comment
//if(this->ordinal == e.getOrdinal()) return true;
//else return false;
return (this->ordinal == e.getOrdinal());
}
inline bool operator!=(const Flag<FlagType>& e) const
{
return !(*this==e);
}
static const std::set<const Flag<FlagType>*>& flagValues()
{
return flagSet;
}
const String& toString() const
{
return name;
}
const size_t& getOrdinal() const
{
return ordinal;
}
static int size()
{
return flagSet.size();
}
static const Flag<FlagType>& valueOf(const String& string)
{
typename std::set<const Flag<FlagType>*>::const_iterator i;
for(i = flagSet.begin(); i != flagSet.end(); i++)
{
if((**i).toString().startsWith(string))
{
return **i;
}
}
throw NotAFlagException();
}
protected:
static std::set<const Flag<FlagType>*> flagSet;
size_t ordinal;
String name;
private:
//added in response to comment to prevent copy and assignment, not compile tested
Flag<FlagType>(const Flag<FlagType>&);
Flag<FlagType>& operator=(const Flag<FlagType>&);
};
template <class FlagType> std::set<const Flag<FlagType>*> Flag<FlagType>::flagSet; //template
项目.hpp
class ItemFlag: public Flag<ItemFlag>
{
public:
static const ItemFlag brick;
private:
ItemFlag(int ordinal, String name):
Flag<ItemFlag>(ordinal, name){}
};
项目.cpp
const ItemFlag ItemFlag::brick(1, "brick");
我的第一篇文章,所以如果我的格式错误或不具体,请告诉我。奇怪的是,用向量替换集合会导致一个工作程序,就好像集合在插入指针时遇到问题一样。为了测试这一点,我用一组 int 替换了该集合,并尝试在类初始化时插入 0,这也导致了相同的错误。
这很容易成为初始化顺序问题。 你基本上需要对集合使用某种延迟初始化,例如
static std::set<Flag<FlagType> const*>& flagSet()
{
static std::set<Flag<FlagType> const*> theOneAndOnly;
return theOneAndOnly;
}
而不是静态变量。
当我在做的时候:这可能不是模板的良好使用。一个更好的解决方案是从一种更简单的格式,大致如下:
[EnumName]
constant_name_1
constant_name_2
等。 可能只需要大约 10 行 AWK、Perl 或Python(根据您的口味)来解析它并输出C++标头和它的C++源文件。 然后,您只需维护简单的格式。
如果类的构造函数将项插入到静态集中,则其析构函数应删除它们。您可能还需要复制构造函数和赋值运算符。麻生太郎,从风格上讲,受保护的数据通常被认为是一件坏事。
不保证不同翻译单元之间的静态初始化顺序。从转储来看,似乎ItemFlag
是在构建集合之前创建的。这会使插入失败。
更改文件名可能会影响文件在链接过程中的顺序。这可以解释为什么以 A 开头的文件会提前链接。
正确执行此操作的唯一方法是在同一.cpp文件中定义集合和ItemFlag
。然后顺序始终是从上到下的。如果它们位于不同的文件中,则链接器决定顺序(通常是随机的)。
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- C++预处理会生成变量成员、资源库和映射
- 局部堆栈变量成员的返回值优化
- Google Mock:在目标类的构造函数中实例化的模拟私有变量成员
- 使用指向结构变量成员的指针访问该结构的成员的地址
- 如果派生类仅包含自动变量成员,是否有必要具有虚拟驱动器
- 线程安全性和静态变量/成员功能
- "static const char array"可以在 C 语言上包含变量成员吗
- 仅用于内部目的的类的所有变量/成员的技术术语是什么
- 如何强制转换变量成员以将其作为函数的引用参数传递
- 类中未声明变量成员函数
- 在 main 中初始化类的 "static const" 类型变量成员的更好方法
- c++模板类静态const变量成员作为映射键给出未定义引用
- 在类中初始化结构变量成员会导致分割错误
- 在c++中建模变量成员类型
- 模板私有静态变量成员的未定义符号
- 不能访问公共静态变量成员
- 常量变量成员在C++有什么用?
- g++ 4.8.2坚持简单变量成员是数组