繁体   English   中英

在std :: bitset :: operator []中创建的std :: bitset :: reference对象的生命周期?

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

我一直在看bitset标准C ++库头文件的头文件。 我发现重载的operator [] operator[](size_t ndx) (在类bitset定义)返回类reference的temproray对象。

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

这个重载的运算符封装了单个位的概念。 此类的实例是实际位的代理。 它在像这样的表达式中很有用

bitset<10> b;
b[2] = true;

reference类定义了overloaded = operator成员函数,以便上面的示例可以工作:

 //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的临时对象,然后在返回的临时对象上调用重载的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])来调用。 临时对象作为评估全表达式([intro.execution])的最后一步被销毁,该表达式(词法上)包含创建它们的点。 即使该评估以抛出异常结束,也是如此。 销毁临时对象的值计算和副作用仅与完整表达相关联,而不与任何特定子表达相关联。

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

实际上,C ++依赖于它,因为这个非常常见的表达式可以正常工作:

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

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


根据class.temporary#5中的规则,临时的生命周期将缩短

有三种情况下,临时表在与完整表达结束时不同的地方被摧毁。 第一个上下文是调用默认构造函数来初始化没有相应初始值设定项的数组元素([dcl.init])。 第二个上下文是在复制整个数组时调用复制构造函数来复制数组元素([expr.prim.lambda],[class.copy])。 在任何一种情况下,如果构造函数具有一个或多个默认参数,则在构造下一个数组元素(如果有)之前,对默认参数中创建的每个临时的销毁进行排序。

并且会在课堂上遵循规则延长。 当前#6

第三个上下文是引用绑定到临时的时间.11引用绑定的临时值或引用绑定到的子对象的完整对象的临时值在引用的生存期内持续存在,除了:

  • 绑定到函数调用([expr.call])中的引用参数的临时对象将持续存在,直到包含该调用的完整表达式完成。

  • 函数返回语句([stmt.return])中返回值临时绑定的生命周期未扩展; 临时在return语句中的full-expression结束时被销毁。

  • 在new-initializer([expr.new])中对引用的临时绑定将持续到包含new-initializer的full-expression完成为止。

在这个例子中可以看到第一个上下文:

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

对于第三种情况下,你可以找到答案在这里 ,并在这里

包含operator bool() if (b[2])的条件是单个表达式,临时值对表达式的整个生命周期有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM