在 std::bitset::operator[] 中创建的 std::bitset::reference 对象的生命周期?
Lifetime of std::bitset::reference object created in std::bitset::operator[]?
我一直在查看 bitset 标准 C++ 库头文件的头文件。我发现重载的 operator[] operator[](size_t ndx)
(在 class bitset
中定义)returns 是 class reference
的临时对象。
reference
operator[](size_t __position)
{ return reference(*this,__position); }
这个重载运算符封装了单个位的概念。 class 的一个实例是实际位的代理。它在
这样的表达式中很有用
bitset<10> b;
b[2] = true;
reference
class 定义了重载的 =
运算符成员函数,因此上面的例子可以工作:
//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]
首先returns一个classreference
的临时对象,然后在返回的临时对象上调用重载运算符(operator bool() const
)将其转换为 bool
数据类型。
// For __x = b[i];
operator bool() const
{ return (*(_M_wp) & _Base::_S_maskbit(_M_bpos)) != 0; }
如果在堆栈上创建临时对象(具有自动存储的对象 class),则调用另一个函数 (operator bool() const
) 不应破坏第一个函数调用返回的临时对象 ( reference
reference operator[](size_t __position)
)?
返回的对象
C 和 C++ 中临时对象的生命周期是多少?
包括 operator bool()
在内的 if (b[2])
中的条件是单个表达式,临时变量在表达式的整个生命周期内都有效。
来自class.temporary#4,强调的是我的
When an implementation introduces a temporary object of a class that has a non-trivial constructor ([class.ctor], [class.copy]), it shall ensure that a constructor is called for the temporary object. Similarly, the destructor shall be called for a temporary with a non-trivial destructor ([class.dtor]). Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression.
该临时对象将在给定表达式的最后一步被销毁。
事实上,C++ 依赖于它,因为这个非常常见的表达式可以正常工作:
int x = 0, y = 0, z = 0, t = 0;
int a = x + y + z + t;
因为x+y
是一个临时的,x+y+z
是另一个临时的。
中的规则,临时文件的生命周期将缩短
There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression. The first context is when a default constructor is called to initialize an element of an array with no corresponding initializer ([dcl.init]). The second context is when a copy constructor is called to copy an element of an array while the entire array is copied ([expr.prim.lambda], [class.copy]). In either case, if the constructor has one or more default arguments, the destruction of every temporary created in a default argument is sequenced before the construction of the next array element, if any.
并且会按照class.temporary#6中的规则延长:
The third context is when a reference is bound to a temporary.116 The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:
A temporary object bound to a reference parameter in a function call ([expr.call]) persists until the completion of the full-expression containing the call.
The lifetime of a temporary bound to the returned value in a function return statement ([stmt.return]) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.
A temporary bound to a reference in a new-initializer ([expr.new]) persists until the completion of the full-expression containing the 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
第三个上下文,你可以在, and here
中找到答案
我一直在查看 bitset 标准 C++ 库头文件的头文件。我发现重载的 operator[] operator[](size_t ndx)
(在 class bitset
中定义)returns 是 class reference
的临时对象。
reference
operator[](size_t __position)
{ return reference(*this,__position); }
这个重载运算符封装了单个位的概念。 class 的一个实例是实际位的代理。它在
这样的表达式中很有用bitset<10> b;
b[2] = true;
reference
class 定义了重载的 =
运算符成员函数,因此上面的例子可以工作:
//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]
首先returns一个classreference
的临时对象,然后在返回的临时对象上调用重载运算符(operator bool() const
)将其转换为 bool
数据类型。
// For __x = b[i];
operator bool() const
{ return (*(_M_wp) & _Base::_S_maskbit(_M_bpos)) != 0; }
如果在堆栈上创建临时对象(具有自动存储的对象 class),则调用另一个函数 (operator bool() const
) 不应破坏第一个函数调用返回的临时对象 ( reference
reference operator[](size_t __position)
)?
C 和 C++ 中临时对象的生命周期是多少?
包括 operator bool()
在内的 if (b[2])
中的条件是单个表达式,临时变量在表达式的整个生命周期内都有效。
来自class.temporary#4,强调的是我的
When an implementation introduces a temporary object of a class that has a non-trivial constructor ([class.ctor], [class.copy]), it shall ensure that a constructor is called for the temporary object. Similarly, the destructor shall be called for a temporary with a non-trivial destructor ([class.dtor]). Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression.
该临时对象将在给定表达式的最后一步被销毁。
事实上,C++ 依赖于它,因为这个非常常见的表达式可以正常工作:
int x = 0, y = 0, z = 0, t = 0;
int a = x + y + z + t;
因为x+y
是一个临时的,x+y+z
是另一个临时的。
中的规则,临时文件的生命周期将缩短
There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression. The first context is when a default constructor is called to initialize an element of an array with no corresponding initializer ([dcl.init]). The second context is when a copy constructor is called to copy an element of an array while the entire array is copied ([expr.prim.lambda], [class.copy]). In either case, if the constructor has one or more default arguments, the destruction of every temporary created in a default argument is sequenced before the construction of the next array element, if any.
并且会按照class.temporary#6中的规则延长:
The third context is when a reference is bound to a temporary.116 The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:
A temporary object bound to a reference parameter in a function call ([expr.call]) persists until the completion of the full-expression containing the call.
The lifetime of a temporary bound to the returned value in a function return statement ([stmt.return]) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.
A temporary bound to a reference in a new-initializer ([expr.new]) persists until the completion of the full-expression containing the 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
第三个上下文,你可以在