具有私有构造函数和自身静态数组的类

Class with private constructor and static array of itself

本文关键字:静态 数组 构造函数      更新时间:2023-10-16

抱歉,如果标题令人困惑,我找不到一种简单的方法来用简单的句子来写它。无论如何,我面临的问题:

 // header:
class SomeThing
{
 private:
   SomeThing() {} // <- so users of this class can't come up
                  //    with non-initialized instances, but
                  //    but the implementation can.
   int some_data; // <- a few bytes of memory, the default
                  //    constructor SomeThing() doesn't initialize it
 public:
   SomeThing(blablabla ctor arguments);
   static SomeThing getThatThing(blablabla arguments);
   static void generateLookupTables();
 private:
   // declarations of lookup tables
   static std::array<SomeThing, 64> lookup_table_0;
   static SomeThing lookup_table_1[64];
};

getThatThing函数旨在从查找表返回实例。

 // in the implementation file - definitions of lookup tables
 std::array<SomeThing, 64> SomeThing::lookup_table_0; // error
 SomeThing Something::lookup_table_1[64]; // <- works fine

我只是不能使用Somethingstd::array,除非我在类中添加一个公共 ctor SomeThing()。它适用于旧式数组,我可以定义数组,并在SomeThing::generateLookupTables()函数中填充它。显然,std::array<SomeThing, 64>类型没有构造函数。关于如何使其工作的任何想法,或者可能是这个概念的更好结构?

============ 编辑 ====

===

friend std::array<SomeThing, 64>方法似乎是一个好主意,但是:

它也将在其他地方的数组中使用。我想保证这个类始终对外部用户保持某些不变性。使用此友好数组,用户可以意外地创建一个未初始化的SomeThing数组。

此外,查找表是使用相当复杂的过程生成的,不能像std::array<SomeThing, 64> SomeThing::lookup_table_0(some value)那样按内联完成

std::array<SomeThing, 64>类在尝试定义实例时显然无法访问private默认构造函数。您可以通过添加

friend class std::array<SomeThing, 64>;

SomeThing的定义.

解决方案:

std::array<SomeThing, 64> SomeThing::lookup_table_0 {{ }};

注意:如此处所述,{{}}需要在 gcc 中对std::array进行值初始化,而不会发出警告。 = {}{}是正确的,但GCC还是警告了。

解决方案的关键是必须存在某种形式的初始值设定项。


首先进行术语检查:所有对象都以C++初始化。这有三种形式,默认值。没有"未初始化"的对象;没有显式初始值设定项的对象称为默认初始化。在某些情况下,这意味着对象的成员变量可能是不确定的("垃圾")。

无初始值设定项版本有什么问题?首先,std::array<SomeThing, 64>的构造函数被定义为已删除,因为声明std::array<SomeThing, 64> x;格式不正确(当然,由于缺少可访问的默认构造函数SomeThing)。

这意味着任何尝试使用默认构造函数进行std::array<SomeThing, 64>的代码反过来都是格式错误的。定义:

std::array<SomeThing, 64> SomeThing::lookup_table_0;

尝试使用默认构造函数,因此格式不正确。但是,一旦开始引入初始值设定项,std::array的默认构造函数就不再起作用;由于std::array是一个聚合,因此会发生聚合初始化,从而绕过隐式生成的构造函数。 (如果有任何用户声明的构造函数,那么它将不再是聚合)。

带有初始值设定项的版本由于 [dcl.init]/13 (n3936) 而工作:

静态成员的初始值设定项位于成员类的范围内

列表初始化的定义在这里将{ }转换为{ SomeThing() }

由于您的构造函数是私有的,因此std::array不能使用它。

您可以在SomeThing中添加friend class std::array<SomeThing, 64>;以授予对构造函数的访问权限。

另一种方法是使用可用的公共构造函数来初始化数组的元素:

std::array<SomeThing, 64> SomeThing::lookup_table_0{
    SomeThing(blablabla_ctor_arguments), ..
};

编辑:

如果你有移动或复制构造函数可用,你甚至可以这样做:

std::array<SomeThing, 64> SomeThing::lookup_table_0{ SomeThing() };

以初始化整个数组默认值。