【问题标题】:Initializing Data Members with a Member Function使用成员函数初始化数据成员
【发布时间】:2014-08-08 19:15:05
【问题描述】:

我今天学习了 C++ 11 非常有用的新特性,它允许在类声明中直接初始化数据成员:

class file_name
{
    public:
    file_name(const char *input_file_name);
    ~file_name();

    private:
    char *file_name=nullptr;  //data_member is initialized to nullptr;
    char *Allocator(int buffer_size);  //code to dynamically allocate requested
                                       //size block of memory.
};

是否可以通过新的 v11 规则更进一步,并使用成员函数的输出来初始化数据成员:

class file_name
{
    public:
    file_name(const char *input_file_name);
    ~file_name();

    private:
    char *file_name=Allocator(MAX_PATH);  //data_member is initialized with a block of
                                          //dynamic memory of sufficient size to hold
                                          //and valid file name.;
    char *Allocator(int buffer_size);  //code to dynamically allocate requested
                                       //size block of memory.
};

这会导致问题吗?

【问题讨论】:

  • 你说得对 - 我把它写在脑海里,因为我倾向于通过引用传递所有变量。也许是错误的?已在 OP 中更改。
  • 要通过引用传递该指针,您必须将其声明为 const char *&input_file_name,而不是原来的 const char &*input_file_name
  • 嗯嗯......违反直觉。正如荷马所说。

标签: c++ memory-management initialization data-members


【解决方案1】:

非静态成员函数(通常)以某种方式依赖于调用它的对象的状态。如果不是这种情况,就没有理由将其设为非静态成员函数。现在你想调用一个依赖于你的对象状态的函数之前说对象被完全构造,即它的函数可能依赖的不变量不一定已经建立。所以使用这样的功能是有潜在危险的,因为例如该函数可能会访问未初始化的变量。考虑这个例子:

class Fail {
    int a = fun() , b;
    int fun() {return b;}
};

这里ab 之前初始化,但具有b 的(未定义)值。 不过静态成员函数应该没问题。

【讨论】:

  • 在我的例子中,分配器纯粹是一个工作函数,对整个对象没有影响。我只把它放在一个函数中,这样我就可以捕捉到任何——看起来不太可能——调用new[]的异常。我想我什至可以把它放在一个外部库中并静态链接到它,但这似乎有点过分了。
  • 如果它不依赖于对象状态,你可以声明它static。 (这与外部库无关。)然后编译器将保护您免受错误。
  • 你能将函数声明为“静态”吗?有趣的!这就是我不断回到 C++ 的原因 - 有很多东西需要探索!
  • 啊……我想我和你在一起。基本上,由于static 成员函数没有this 指针,它们不能直接更改其父类的数据成员。太棒了!
【解决方案2】:

用于成员初始化的大括号或相等初始化器在标准中定义,在第 9.2 节。第 4 点说 “大括号或等式初始化器应仅出现在数据成员的声明中。”

构造过程中成员的初始化在第 12.6.2 节中描述。​​
第 10 点描述了顺序:1)大多数派生基类,2)直接基类初始化器,3)非静态数据成员 4)构造函数的复合语句。

这意味着当你的数据成员括号或相等初始化器被调用时,基类(你的类)总是被初始化。

该部分的第 13 点说:“可以为正在构建的对象调用成员函数(包括虚成员函数)。”...“但是,如果这些操作在 ctor-initializer 中执行(或在直接调用的函数中 或间接来自 ctor-initializer) 在基类的所有 mem-initializers 完成之前,操作的结果是未定义的。 "。最后一个例外不应该发生在你的情况下。

所以是的,这种说法应该是有效的。

编辑: 根据 12.6.2 pt.8,仅当对象的构造函数没有成员的 mem-initializer(即具有“:”语法的初始化器)时,才使用大括号或相等初始化器

【讨论】:

  • 顺便说一下,我可以用 MSVC 2013 编译代码,有 2 处调整:1) const char *&input_file_name,2) 重命名私有成员,因为它不允许与类本身。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-26
  • 2021-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多