使用g ++ 4.9和clang 3.4进行测试,为什么这段代码无法编译:
namespace {
template<typename T>
constexpr auto f(T && t) noexcept {
return true;
}
template<typename T, typename... Ts>
constexpr auto f(T && t, Ts && ... ts) noexcept(noexcept(f(ts...))) {
return f(ts...);
}
} // namespace
int main() {
f(true, 0, 5u);
}
Run Code Online (Sandbox Code Playgroud)
但是这段代码确实:
namespace {
template<typename T>
constexpr auto f(T && t) noexcept {
return true;
}
template<typename T>
constexpr auto f_helper(T && t) noexcept(noexcept(f(t))) {
return f(t);
}
template<typename T, typename... Ts>
constexpr auto f_helper(T …Run Code Online (Sandbox Code Playgroud) template <class T>
struct Obj {
// Plain Old Data for T
using InternalPod = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
InternalPod value_pod_;
template<class... Args>
Obj(Args&&... args) { // my constructor
// placement new: construct the value in the statically allocated space
new (&value_pod_) T(std::forward<Args>(args)...); // <- can this whole expression throw if the constructor of T doesn’t throw?
}
}
Run Code Online (Sandbox Code Playgroud)
new如果分配失败或者构造失败,则抛出正常(如果有其他情况,则纠正我),但由于放置new不分配任何空间,如果构造函数T不抛出,新表达式是否可以抛出?
即以下noexcept规范是否正确且安全?
Obj(Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
new (&value_pod_) T(std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud) 在阅读关于C++ 11时,我感觉当使用标准容器(如std::vector)和用户定义的数据类型时,鼓励人们提供noexcept移动操作,如果有的话,因为那时候容器会在内部真正移动数据而不是复制.
今天尝试时,我发现-std=c++1y(对于C++ 14)和g ++ - 4.8都没有区别.也许我错过了规范中的更新,也许我的例子是错误的.
我比较了三个应该可以移动的数据结构
noexceptnoexcept框架:
#include <string>
#include <vector>
#include <chrono>
#include <iostream> // cout
using std::vector; using std::cout;
using namespace std::chrono;
long long millisSeit(steady_clock::time_point start) {
return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
namespace {
constexpr size_t ITERATIONS = 1000*1000;
template<typename ELEM>
void timeStuff(std::string name) {
cout << name << "...";
auto start = steady_clock::now();
std::vector<ELEM> data{};
for(size_t idx=0; idx<ITERATIONS; ++idx) {
data.emplace_back( idx …Run Code Online (Sandbox Code Playgroud) 对于某些标准库类,对其部分内容的访问可能会合法地失败。通常你可以在一些潜在的抛出方法和一个被标记的方法之间进行选择noexcept。后者免去了对前提条件的检查,所以如果你想自己承担责任,你可以。这可以在不允许使用异常或修复性能瓶颈的情况下使用。
示例 1:std::vector元素访问:
std::vector<int> vec;
vec.at(n) // throws std::out_of_range
vec[n] // potentially UB, thus your own responsibility
Run Code Online (Sandbox Code Playgroud)
示例 2:std::optional访问:
std::optional<int> optn;
optn.value() // throws std::bad_optional_access
*optn // potentially UB, thus your own responsibility
Run Code Online (Sandbox Code Playgroud)
现在到std::variant. 直接访问替代品在某种程度上遵循以下模式:
std::variant<std::string, int> var;
std::get<int>(var) // potentially throwing std::bad_variant_access
*std::get_if<int>(&var) // potentially UB, thus your own responsibility
Run Code Online (Sandbox Code Playgroud)
但这一次签名发生了变化,我们必须注入*和&。这样做的缺点是我们没有获得自动移动语义。还有一件事要记住......
但如果你看一下,情况会变得更糟std::visit(Visitor&& vis, Variants&&... vars)。它别无选择noexcept,虽然它只会抛出
如果 vars 中的任何变体是valueless_by_exception。
这意味着对于访问变体您不能选择自己承担责任,如果您别无选择且必须避免异常,则您根本无法std::variants使用标准工具访问!(除了可怕的解决方法 …
我正在处理一些constexpr使用函数的代码,我目前consteval尽可能将其重构为。
inline constexpr auto example() noexcept { /*...*/ }
Run Code Online (Sandbox Code Playgroud)
据我了解,inline上面的关键字在constexpr函数中已经是多余的了。
据我所知,noexcept关键字对于consteval函数来说是多余的,因为据我所知,它consteval必须在编译时进行评估,因此意味着 noexcept。这是真的还是我目前不考虑的东西(比如 constexpr exceptions)?
consteval auto example() { /*...*/ }
Run Code Online (Sandbox Code Playgroud) 根据文档, std::string_view 有一个带有 aconst char *和 a的构造函数std::size_t,但未声明noexcept:
constexpr basic_string_view(const CharT* s, size_type count);
Run Code Online (Sandbox Code Playgroud)
另一方面,文档还声明了用户定义的文字operator""sv,在我见过的所有实现中都是该构造函数的简单包装器,已声明noexcept:
constexpr std::string_view operator "" sv(const char* str, std::size_t len) noexcept;
Run Code Online (Sandbox Code Playgroud)
你知道这种差异的原因吗?构造函数什么时候可以抛出?
似乎 MSVC 将所有 lambda 都视为 noexcept。此代码在 msvc 19.28 中编译(在编译器资源管理器中检查),但预计会在 gcc 中失败静态断言:
void foo() {
auto lambda_may_throw = [] {};
static_assert(noexcept(lambda_may_throw()));
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,我用谷歌搜索了一下,但无法找到有关此问题的任何信息。这真的是 msvc 错误还是只是我没明白什么?
有些函数应该是非抛出的,但标准对此没有任何说明。例如erase(q)(q表示有效的可解引用常量迭代器)的关联容器。根据[res.on.exception.handling#4],这允许实现抛出任何标准异常:
C++ 标准库中定义的函数没有 Throws: 段落,但具有潜在抛出异常规范,可能会抛出实现定义的异常。170 实现应通过抛出标准异常类或派生自标准异常类的异常来报告错误([坏.alloc]、[support.exception]、[std.exceptions])。
因此,如果您想吞掉它们抛出的任何实现定义的异常,则必须使用 try-catch 块。
std::set<int> s{1};
try
{
s.erase(s.cbegin());
}
catch (...) {}
Run Code Online (Sandbox Code Playgroud)
它丑陋且低效,但却是必要的。所以我也不知道这样做有什么好处。
我正在使用此处列出的书籍学习 C++ 。我编写了以下示例(纯粹出于学术原因),该示例使用 GCC 进行编译,但不使用 Clang 和 MSVC 进行编译。演示。
struct C {
static bool f() noexcept(!noexcept(C::f()))
{
return true;
}
};
Run Code Online (Sandbox Code Playgroud)
正如我们在这里看到的,上面的示例使用 gcc 进行编译,但不使用 msvc 和 clang 进行编译。
所以我的问题是哪个编译器就在这里(如果有的话)。
GCC 编译了这个。
MSVC 说:
<source>(2): fatal error C1202: recursive type or function dependency context too complex
Run Code Online (Sandbox Code Playgroud)
铿锵 说:
<source>:2:40: error: exception specification is not available until end of class definition
static bool f() noexcept(!noexcept(C::f()))
Run Code Online (Sandbox Code Playgroud) 我理解容器可以优化具有noexcept移动构造函数/赋值/交换的类型.但是,是否有实际的原因(除了文档)指定其他操作noexcept?
具体来说,我感兴趣的是,如果标准库中有优化,还可以通过以下方式获得noexcept: