- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我试图尽可能接近 强异常保证,但是在玩弄 std::move_if_noexcept
时,我遇到了一些看似奇怪的行为。
尽管下面的类中的移动赋值操作符被标记为noexcept
,复制赋值操作符在被调用时被调用带有相关函数的返回值。
struct A {
A () { /* ... */ }
A (A const&) { /* ... */ }
A& operator= (A const&) noexcept { log ("copy-assign"); return *this; }
A& operator= (A&&) noexcept { log ("move-assign"); return *this; }
static void log (char const * msg) {
std::cerr << msg << "\n";
}
};
int main () {
A x, y;
x = std::move_if_noexcept (y); // prints "copy-assign"
}
最佳答案
move_if_noexcept
的名称当然暗示该函数将产生一个 rvalue-reference,只要这个操作是 noexcept
,并且有了这个请记住,我们很快就会意识到两件事:
T&
到 T&&
或 T const&
的简单转换永远不会抛出异常,那么这样的函数的目的是什么?move_if_noexcept
如何神奇地推断出使用返回值的上下文?实现的答案(2) 既可怕又自然; move_if_noexcept
根本无法推断出这样的上下文(因为它不是读心器),这反过来又意味着该函数必须按照一些静态规则来运行。
move_if_noexcept
将根据参数类型的异常规范 move- 有条件地返回一个 rvalue-reference constructor,它仅用于初始化对象时(即不分配给它们时)。
template<class T>
void intended_usage () {
T first;
T second (std::move_if_noexcept (first));
}
更好的名字应该是 move_if_move_ctor_is_noexcept_or_the_only_option
;虽然打字有点乏味,但至少可以表达预期的用途。
move_if_noexcept
阅读产生 std::move_if_noexcept
的提案 (n3050 ),我们发现以下段落(强调我的):
We propose that instead of using
std::move(x)
in those cases, thus granting permission for the compiler to use any available move constructor, maintainers of these particular operations should usestd::move_if_noexcept(x)
, which grants permission move unless it could throw and the type is copyable.Unless
x
is a move-only type, or is known to have a nonthrowing move constructor, the operation would fall back to copyingx
, just as thoughx
had never acquired a move constructor at all.
move_if_noexcept
是做什么的?std::move_if_noexcept
将有条件地将传递的 lvalue-reference 转换为 rvalue-reference,除非;
// Standard Draft n4140 : [utility]p2
template<class T>
constexpr conditional_t<
!is_nothrow_move_constructible::value && is_copy_constructible<T>::value,
const T&, T&&
> move_if_noexcept (T& x) noexcept;
这基本上意味着它只会产生一个 rvalue-reference 如果它可以证明它是唯一可行的替代方案,或者如果它保证不会抛出异常(通过 表示没有异常(exception)
)。
std::move
是对 rvalue-reference 的无条件强制转换,而 std::move_if_noexcept
取决于对象可以使用的方式是 move-constructed - 因此它应该只在我们实际构造对象的地方使用,而不是在我们分配对象时使用。
由于 move_if_noexcept
找不到标记为 noexcept
,但由于它有一个 copy-constructor,该函数将产生一个适合这种情况的类型,A const&
。
请注意 copy-constructor 有资格作为 MoveConstructible 的类型,这意味着我们可以让 move_if_noexcept
返回一个 rvalue-reference 通过对您的代码段进行以下调整:
struct A {
A () { /* ... */ }
A (A const&) noexcept { /* ... */ }
...
};
struct A {
A ();
A (A const&);
};
A a1;
A a2 (std::move_if_noexcept (a1)); // `A const&` => copy-constructor
struct B {
B ();
B (B const&);
B (B&&) noexcept;
};
B b1;
B b2 (std::move_if_noexcept (b1)); // `B&&` => move-constructor
// ^ it's `noexcept`
struct C {
C ();
C (C&&);
};
C c1;
C c2 (std::move_if_noexcept (c1)); // `C&&` => move-constructor
// ^ the only viable alternative
struct D {
C ();
C (C const&) noexcept;
};
C c1;
C c2 (std::move_if_noexcept (c1)); // C&& => copy-constructor
// ^ can be invoked with `T&&`
关于c++ - 即使 move-assignment 是 noexcept,std::move_if_noexcept 也会调用 copy-assignment;为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28598488/
考虑: class test { private: int n; int impl () const noexcept { return
#include class A { std::vector vec; void swap( A & other) noexcept(noexcept(vec.swap(other.
在 the C++ standard有如下定义: template void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a,
从 c++20 开始,我们可以使用 consteval 说明符定义立即数函数。当一个函数被声明为 consteval 时,对该函数的每次调用都必须产生一个编译时常量,否则该程序就是病式的。此外,由于
为什么 noexcept 运算符采用表达式而不是函数签名/声明? 考虑以下虚拟示例: #include void strProcessor(const std::string& str) noexc
我有一段通用代码,其性能对我来说很重要,因为我面临着与用 C 编写的著名手工代码的运行时间相匹配的挑战。在开始使用 noexcept 之前,我的代码运行时间为 4.8 秒。通过将 noexcept 放
如果我将函数标记为 noexcept(false),或任何其他计算结果为 false 的表达式,这意味着什么? (1) 我是否向编译器保证该函数可以抛出异常?,(2) 还是我不保证它是否可以抛出异常?
我们遇到过这种情况,想知道解决它的最佳方法 template struct A : T { A(T &&t) noexcept(noexcept(T(std::move(t)))) :T
此代码使用 gcc 4.8.2 (-std=c++11) 编译失败,但使用 clang 3.4 (trunk) (-std=c++11) 编译: #include #include struct
当函数标记为 noexcept 时,GCC 或 Clang 中是否有一个标志会抛出编译时错误(或警告)尝试调用未标记为 noexcept 的函数? 如果不是,那么当您删除 noexcept 时,您应该
假设我有一个类 class C : public B { public: C() noexcept; } noexcept 说明符是否需要基类的相同 promise ?也就是说,当我考虑使
长标题:为什么 std:variant 的 operator=(T&& t) 的 noexcept 规范不依赖于内部类型的析构函数的 noexcept 规范? 我可以在 cppreference 上看
在下面的代码中,我尝试对函数使用条件异常规范,但编译失败,尽管如果在函数外部使用它就可以了。 void may_throw(); // ERROR: expression must have bool
目前在C++这些都不可能,编译器提示它需要一个表达式。 这对我来说似乎微不足道,如果您正在构建一个具有可变数量类型的类似元组的对象,如何检查所有这些类型是否都是 nothrow default/mov
在 The C++ Programming Language 一书中写道,您可以将函数声明为有条件的 noexcept .例如: template void my_fct(T& x) noexcept
根据this question的回答,默认移动构造函数可以定义为 noexcept在一定条件下。例如,下面的类生成一个 noexcept移动构造函数: class C {}; 根据对this ques
拿这个代码: template void my_func() { T::some_method(); } int main() { std::cout ()) ? "noexcept" :
这个声明没问题: void memberFunction(T& functor, double value)noexcept(noexcept(functor(value))); 对于一个 templ
我在思考 noexcept 时遇到了一些麻烦。 template int pop(int idx) noexcept(noexcept(SIZE > 0)) // this is what I do
为什么 std::decay 不从函数指针中移除 noexcept 说明符? 例如这符合 c++17 #include template struct is_noexcept {}; templat
我是一名优秀的程序员,十分优秀!