STD :: BITSET ::参考对象在STD :: BITSET ::操作员[]中创建的寿命

Lifetime of std::bitset::reference object created in std::bitset::operator[]?

本文关键字:STD BITSET 创建 操作员 参考 对象      更新时间:2023-10-16

我一直在查看BITSET标准C 库标头的标头文件。我发现过载的运算符[] operator[](size_t ndx)bitset类定义)返回类reference的TEMPRORAY对象。

reference
    operator[](size_t __position)
{ return reference(*this,__position); }

这个超载的操作员封装了一个位的概念。此类的一个实例是实际位的代理。它在

之类的表达式中很有用
bitset<10> b;
b[2] = true;

reference类已定义了重载的=运算符成员函数,以便上述示例可以工作:

 //For b[i] = __x;
 reference&
     operator=(bool __x)
 {
   if (__x)
     *_M_wp |= _Base::_S_maskbit(_M_bpos);
   else
     *_M_wp &= ~_Base::_S_maskbit(_M_bpos);
   return *this;
}

但是,我对此表达感到困惑:

if (b[2]) {
    //Do something
}

b[2]首先返回类reference的临时对象,然后在该返回的临时对象上调用Overloaded Operator(operator bool() const)将其转换为bool数据类型。

// For __x = b[i];
operator bool() const
{ return (*(_M_wp) & _Base::_S_maskbit(_M_bpos)) != 0; }

如果在堆栈上创建了临时对象(具有自动存储类的对象),则调用另一个函数(operator bool() const)不应破坏第一个函数调用返回的临时对象(reference对象reference operator[](size_t __position)返回)?

C和C 中临时对象的寿命是什么?

来自class.temporary#4,强调是我的。

实现引入具有非平凡构造函数的类的临时对象([class.ctor],[class.copy])时,应确保将构造函数称为临时对象。同样,应要求使用非平凡的破坏者([class.dtor])暂时命令驱动器。临时对象被破坏为评估全表达([Into.exection])(词法)包含创建点的最后一步。这是正确的一个例外。破坏临时对象的价值计算和副作用仅与全表达相关,而不与任何特定的子表达相关联。

该临时对象将在该给定表达式的最后一步被破坏。

实际上,C 依赖于此非常常见的表达可以正确工作:

int x = 0, y = 0, z = 0, t = 0;
int a = x + y + z + t;

因为x+y是临时的,x+y+z是另一个临时。


临时寿命将在类规则中缩短。

在三个上下文中,临时性在与全表达的末端不同的点上被摧毁。第一个上下文是调用默认构造函数来初始化不相应的初始化器([dcl.init])的数组的元素。第二个上下文是调用复制构造函数在复制整个数组时复制数组的元素([[Expr.prim.lambda],[class.copy])。无论哪种情况,如果构造函数都有一个或多个默认参数,则在构建下一个数组元素之前对默认参数中创建的每个临时性的破坏进行测序,如果有的话。

它将在类中延长遵循规则。

第三个上下文是当引用绑定到临时性时。116参考所绑定的临时性或临时是一个子对象的完整对象。:

  • 一个临时对象绑定到函数调用中的参考参数([expr.call]),直到包含调用的全表达完成为止。

  • 未延长函数返回语句([stmt.return])中返回值的临时绑定的寿命未扩展;临时性在返回语句中的全表达结束时被销毁。

  • 临时绑定到新的initializer([expr.new])中的参考文献,直到完成包含新的initializer的全表达完成。

在此示例中可以看到第一个上下文:

struct bar {
    bar() { std::cout << __func__ << 'n'; }
    bar(const bar&) { std::cout << __func__ << "__n"; }
    ~bar() { std::cout << __func__ << 'n'; }
};
struct foo {
    foo(const bar& b = bar()) { std::cout << __func__ << 'n'; }
};
int main() {
    foo f[] = {foo(), foo()};
}

上面的程序应输出:

bar
foo
~bar
bar
foo
~bar

第二个上下文将添加到C 17中,此后此程序:

struct bar {
    bar() { std::cout << __func__ << 'n'; }
    bar(const bar&) { std::cout << __func__ << "__n"; }
    ~bar() { std::cout << __func__ << 'n'; }
};
struct foo {
    foo() {}
    foo(const foo&, const bar& b = bar()) { std::cout << __func__ << "__n"; }
};
struct foox {
    foo f[2];
};
int main() {
    foox fx;
    foox yx = fx;
}

必须输出:

bar
foo__
~bar
bar
foo__
~bar

在第三个上下文中,您可以在此处找到答案,此处

if (b[2])中的条件在内,包括 operator bool()是一个表达式,临时性对于表达式的整个生命周期都是有效的。