如果std::vector<T>
at的存储空间不足emplace_back()
,则使用copy构造函数将元素复制到新的存储中,如果T
的move构造函数不是noexcept
。该程序打印copy!
(godbolt):
#include <vector>
#include <cstdio>
struct T {
T() = default;
T(T &&) { printf("move!\n"); }
T(const T &) { printf("copy!\n"); }
};
int main() {
std::vector<T> v;
v.emplace_back();
v.emplace_back();
}
如果我用标记移动构造函数,则将noexcept
打印此程序move!
。所有这些都是可以预期的。
现在,由于我不编写使用异常的代码,所以我使用来关闭异常-fno-exceptions
。而且我希望我的示例(没有noexcept
)可以打印出来move!
。但是,GCC和clang仍然会打印copy!
。
该行为是否由标准规定?还是允许编译器使用move
,只是没有针对这种情况进行优化?
标准没有说明关闭异常时会发生什么。ISO C ++是一种没有变体的单一语言,通过停用例外,您可以切换到标准不再涵盖的方言。
一个实现可以选择启用您要求的功能,但是这样做需要库实现付出更多的努力。对于标准的一致性实现,是否移动或复制的决定将基于std::is_nothrow_move_constructible
,该决定仅基于该决定基于noexcept
移动构造函数签名中的说明符,而不取决于构造函数是否实际引发异常。为了实现您的期望,该实现必须为-fno-exceptions
方言实现一种不同的检测机制,并将其作为非标准扩展名。
标准中的相关段落为[vector.modifiers]:
template<class... Args> constexpr reference emplace_back(Args&&... args);
[...]如果在在端部插入单个元件的抛出异常,并且
T
是Cpp17CopyInsertable或is_nothrow_move_constructible_v<T>
是true
,没有影响。
即使不是很明显,这is_nothrow_move_constructible_v
也会在false时强制调用副本构造函数,因为这是实现符合此要求的唯一方法。请注意,在该标准的早期版本中,情况更加微妙。C ++ 11草案仅说明:
如果non-的moveconstructor抛出异常
CopyInsertable T
,则效果未指定。
实际上是哪种行为与新措词具有相同的行为。
现在,从理论上讲,如果实现具有其他功能来检测函数是否除了查找之外noexcept
(例如,通过对move构造函数的实现进行静态分析)是否可以抛出该函数,是否仍允许它在C ++ 11的措辞下移动?答案是肯定的,但是我不知道为实现如此良性的优化而付出的巨大努力。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句