gpt4 book ai didi

c++ - 对于具有抛出复制构造函数和 noexcept 按值复制赋值的类,is_nothrow_copy_assignable 的值是多少?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:18:56 24 4
gpt4 key购买 nike

根据 C++ 标准,以下程序的预期(如果有)输出是什么:

#include <iostream>
#include <iomanip>
#include <type_traits>

class A {
public:
A() = default;
~A() = default;
A(A const& other) {}
A(A&& other) noexcept {}
A& operator=(A other) noexcept { return *this; }
};

int main() {
std::cout << std::boolalpha
<< std::is_nothrow_copy_assignable<A>::value << "\n"
<< std::is_nothrow_move_assignable<A>::value << "\n";
}

换句话说,类型特征值的评估是否只看赋值运算符的声明,即 noexcept,并因此产生

true
true

或者它是否考虑调用上下文( abA 的实例)

a = b;            // may throw, implicitly calls copy c'tor
a = std::move(b); // noexcept, implicitly calls move c'tor

它是否产生

false
true

实践尝试

使用 Visual Studio 2015 运行代码,Update 3 提供

true
true

而 gcc 6.1 给出了

false
true

谁是对的?

背景

当我们有一个带有抛出复制构造函数(因为资源分配可能会失败)、一个 noexcept 移动构造函数、一个抛出复制赋值和一个 noexcept 移动赋值的资源管理类时,就会出现这种情况。

假设复制和移动分配都可以根据交换 IDOM 有效地实现:

A& operator=(A const& other) {
A(other).swap(*this); // calls the copy c'tor, may throw
return *this;
}

A& operator=(A&& other) noexcept {
A(std::move(other)).swap(*this); // calls noexcept move c'tor
return *this;
}

然后我们可能会考虑将两者压缩成单个按值复制分配

A& operator=(A other) noexcept {
other.swap(*this);
return *this;
}

但是,我们只有在 std::is_nothrow_copy_assignable<A> 时才能安全地执行此操作和 std::is_nothrow_move_assignable<A>提供正确的值(分别为 false 和 true)。否则,依赖于这些类型特征的代码会表现得很糟糕,我们的单个按值赋值将不能正确地替代两个单独的赋值运算符。

最佳答案

is_nothrow_copy_assignable的定义在 [meta.unary.prop] 中:

For a referenceable type T, the same result as is_nothrow_assignable_v<T&, const T&>, otherwise false.

好的,A是可引用的(意思是 A& 是有效的)。所以我们进入is_nothrow_assignable :

is_assignable_v<T, U> is true and the assignment is known not to throw any exceptions (5.3.7).

is_assignable_v<A, A const&>绝对是true , 所以我们满足第一部分。众所周知不抛出任何异常是什么意思?根据 [expr.unary.noexcept]:

The noexcept operator determines whether the evaluation of its operand, which is an unevaluated operand (Clause 5), can throw an exception (15.1). [...] The result of the noexcept operator is true if the set of potential exceptions of the expression (15.4) is empty, and false otherwise.

在 [except.spec] 中:

The exception-specification noexcept or noexcept(constant-expression), where the constant-expression yields true, denotes an exception specification that is the empty set. The exception-specification noexcept(constant-expression), where the constant-expression yields false, or the absence of an exception-specification in a function declarator other than that for a destructor (12.4) or a deallocation function (3.7.4.2) denotes an exception specification that is the set of all types.

和:

The set of potential exceptions of an expression e is empty if e is a core constant expression (5.20). Otherwise, it is the union of the sets of potential exceptions of the immediate sub-expressions of e, including default argument expressions used in a function call, combined with a set S defined by the form of e, as follows: [...]
— If e implicitly invokes one or more functions (such as an overloaded operator, an allocation function in a new-expression, or a destructor if e is a full-expression (1.9)), S is the union of:
   — the sets of types in the exception specifications of all such functions, and
   — if e is a new-expression [...]

现在,一个 A 的赋值来自 A const&包括两个步骤:

  1. 调用A的拷贝构造函数
  2. 调用A 的复制赋值运算符|

异常规范是这两个函数的所有异常规范的 union ,它是所有类型的集合——因为复制构造函数根本没有异常规范

因此,is_nothrow_copy_assignable_v<A>应该是 false . gcc 是正确的。

关于c++ - 对于具有抛出复制构造函数和 noexcept 按值复制赋值的类,is_nothrow_copy_assignable 的值是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42034848/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com