【问题标题】:C++: lifetime of an object and external functionsC++:对象的生命周期和外部函数
【发布时间】:2015-08-01 17:27:36
【问题描述】:

假设我想调用对象的外部函数来在主体构造函数中执行一些检查。由于对象的生命周期从构造函数的主体完成执行开始,这是一个不安全的设计吗?

struct A;

void check(A const&) { /* */ }

struct A
{
    A() { check(*this); }
};

我的意思是,我正在调用一个尚未激活的对象的外部函数。是未定义的行为吗?

相关问题:如果我将该检查函数作为成员函数(静态或非静态),标准对在构造函数外部但在类内部使用非活跃对象有何规定?

在类和它的用户的观点之间的生命周期概念有什么不同(一种类内与类外的生命周期)?

【问题讨论】:

  • C++ FAQ 有相关信息。
  • 应该没问题,只要函数不是virtual的成员并且不在初始化列表中
  • 一个 const& 是一个引用,在检查开始时既不初始化也不在函数结束时销毁。除了在构造函数内部,对象是完全构造的。我在这段代码中没有看到任何问题
  • @JesseGood 我读过这个问题,还有这个问题:isocpp.org/wiki/faq/ctors#init-methods。所以,isocpp FAQ 是在 C++11 时代之前,我知道关于对象生命周期的规则在新标准中已经改变。虽然非常有用,但我希望对规则保持安全。
  • @RobK 符合标准。我正在向外部函数发送一个定义明确(对象已初始化)但非活动的对象。这样做的正式后果是什么?以后怎么跟儿子解释呢? :)

标签: c++ constructor language-lawyer object-lifetime


【解决方案1】:

A 的生命周期不会在调用 check() 时开始,因为来自 [base.life]:

T 类型对象的生命周期开始于:

  • 获得了与 T 类型正确对齐和大小的存储,并且
  • 如果对象有非空初始化,则其初始化完成。

A 具有非空初始化。它的初始化完成时,从 [class.base.init]/13:

在非委托构造函数中,初始化按以下顺序进行:

  • ...
  • ——最后,构造器主体的compound-statement被执行。

然而,尽管A 的生命周期尚未开始,该标准还在 [class.base.init]/16 中提供:

可以为正在构造的对象调用成员函数(包括虚拟成员函数,10.3)...但是,如果这些操作在 ctor-initializer 中执行(或在直接调用的函数中 或间接来自 ctor-initializer)在所有基类的 mem-initializers 完成之前,操作的结果是未定义的。

关于生命周期问题,两者没有区别:

void check(const A& ) { .. }
struct A { 
    A() { check(*this); } 
};

还有:

struct A {
    void check() const { .. }
    A() { check(); }
};

后者是明确允许的(因为它不在 ctor-initializer 中),所以我认为没有理由以生命周期为由排除前者。

【讨论】:

  • ... 除非 A 是具有由check() 调用的虚拟成员的基类 - 那么结果可能会让您大吃一惊。
  • @RichardHodges 这不是未定义的行为。
  • @Barry 你确定初始化在那里结束吗? stackoverflow.com/a/20409911/1794803
  • @RichardHodges 这不是巴里所说的未定义行为。简单地说,动态多态性在派生对象完全构造之前不起作用(因为之前构造了基础对象),而是调用基础重载。
  • 所以,所以。该标准不允许从主体构造函数调用外部函数(前提是子对象已初始化),但也声明该对象尚未存活。那么以这种方式定义生命有什么意义呢?用实际上不存在的对象调用外部函数有什么意义?说对象在构造完成之前还没有存活是有道理的,但是,不定义生命周期或类似的东西不是更好吗?
猜你喜欢
  • 1970-01-01
  • 2013-09-25
  • 1970-01-01
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-02
相关资源
最近更新 更多