【问题标题】:Construction of const objectconst对象的构造
【发布时间】:2012-02-03 01:35:46
【问题描述】:

C++11 §12.1/14:

在构造 const 对象期间,如果对象或其任何子对象的值通过左值访问 不是从构造函数的 this 中直接或间接获得的 指针,由此得到的对象或子对象的值为 未指定。 [示例:

struct C;
void no_opt(C*);

struct C {
    int c;
    C() : c(0) { no_opt(this); }
};

const C cobj;

void no_opt(C* cptr) {
    // value of cobj.c is unspecified
    int i = cobj.c * 100;
    cptr->c = 1;
    // value of cobj.c is unspecified
    cout << cobj.c * 100 << '\n';
}

编译上述示例输出100。我的问题是为什么在进入构造函数之前初始化列表将其设置为0 时,cobj.c 的值应该是未指定的?如果使用非常量对象,这种行为有何不同?

【问题讨论】:

  • 我会注意到,在上面的示例中,cobj.c 是在 cobj 完全构造之前访问的。在我看来,即使对于非 const 对象,这个动作也是可疑的。
  • @MatthieuM。为什么?对我来说看起来有效(即使您将基类添加到结构 C)。
  • @VJovic:只要构造函数还没有运行,对象就不是活着的——参见 Sutter 对Constructor Failures (or, The Objects That Never Were) 的看法。如果一个对象还没有活着,访问它是可疑的。我并不是说它一定是未定义或未指定的,只是它“闻起来很糟糕”。
  • 我不明白措辞。 cptr 是从 this 获得的,但引用说“not 获得”(否则如何)?另外,这个引用意味着构造函数体不得修改任何成员,否则 const 对象的行为将未指定?
  • @visitor:问题是在构造函数返回之前使用cobj。读取权限是有问题的。

标签: c++ constructor constants


【解决方案1】:

真正的const 对象可能会被编译器视为合法常量。它可以假设它们的值永远不会改变甚至将它们存储在const 内存中,例如ROM 或闪存。因此,您需要使用this 提供的非常量访问路径,只要对象实际上不是常量即可。这种情况只存在于对象的构造和销毁过程中。

顺便说一句,我认为不需要对析构函数有相应的要求,因为对象的生命周期已经结束,并且一旦cobj 的析构函数开始,cobj.c 就无法访问。

正如 Matthieu 所提到的,在构造或销毁期间通过this 访问对象是一种强烈的“代码气味”。回顾 C++11 §3.8 [basic.life] ¶1 和 6,构造函数内的 cobj.c 似乎是 UB,原因与它在析构函数内的原因相同,无论对象是 const 还是 §12.1 /14,因为它的生命周期直到初始化完成(构造函数返回)才开始。

它可能会起作用,但它会给优秀的 C++ 程序员敲响警钟,而且从书上看它是非法的。

【讨论】:

  • C() : c(0) { c=1; } - 所以你的意思是这也是无效的?
  • 这似乎离题了:它没有解决cobj.cC 的构造函数运行期间具有未指定值的事实(即使在初始化列表运行之后)。它也没有解决为什么 const 和非 const 对象之间的行为会有所不同(在这方面)。
  • @MatthieuM。我想我已经涵盖了这两个问题。问题是编译器可以将cobj.c 访问路径识别为具有无法更改的值。无论是什么函数访问它,一个没有常量值的const 对象都是禁止使用的。
  • 啊,我终于明白了你所说的“非常量访问路径”,抱歉太密集了。
【解决方案2】:

引用规则的原因是允许编译器使 基于对象的 const-ness 的优化。例如, 根据优化,您的编译器可能会替换第二个 cobj.c * 100no_opti。更有可能的是,在这个特定的 在这种情况下,优化器将抑制 i 及其初始化 完全,所以代码似乎可以工作。但这可能不是 如果您还输出i,则在更改cptr-&gt;c之前的情况下;这一切都取决于 关于编译器优化的积极程度。但是允许编译器 假设*cptr 不是cobj 的别名,因为cobj 是 const 对象,当您通过*cptr 进行修改时,它不能指向 没有未定义行为的 const 对象。

如果对象不是 const,当然不会出现问题;这 编译器必须始终考虑到可能的别名 *cptrcobj

【讨论】:

    猜你喜欢
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多