c++ - 在 decltype() 或 operator noexcept() 上下文中对 nullptr 使用 placement new

标签 c++ c++11 c++14 decltype noexcept

标准是否允许写decltype(::new (nullptr) T(std::declval< Args >()...))noexcept(::new (nullptr) T(std::declval< Args >()...)) ?特别感兴趣的安置newnullptr正确性。考虑以下代码:

#include <type_traits>
#include <utility>

struct S { S(int) { ; } ~S() = delete; };

struct A
{
    template< typename T,
              bool is_noexcept = noexcept(::new (nullptr) S(std::declval< T >())) >
    A(T && x) noexcept(is_noexcept)
        : s(new S(std::forward< T >(x)))
    { ; }

    S * s;
};

static_assert(std::is_constructible< A, int >{});
static_assert(!std::is_constructible< A, void * >{});

禁用器 typename = decltype(S(std::declval< T >()))需要存在析构函数,但放置 new不是。

尽管如此,decltype 的上下文仍未计算和运算符 noexcept我想知道是否符合标准。因为编译器可能会证明测试表达式 100% 不正确。

最佳答案

在标准的所有已发布版本中,可以将空指针传递给新位置,并且要求编译器处理这种情况,因此代码如果调用 ::operator new(size_t, void*) 是可以的。带有一个空指针。

但是,一个类可能会重载 operator new(size_t, nullptr_t)在这种情况下,您的表达式将使用它,因此您无法确切知道会发生什么(例如,它可能被删除,或者它可能是 noexcept(false) )。

在 C++17 的工作草案中,如果保留位置分配函数返回空值,则为未定义行为(这在 a question I asked here and on the committee lists 引起的讨论后已更改)。目前尚不清楚这是否意味着它实际被调用并返回 null,或者您的用法是否未定义。

我宁愿不要冒险,而是会使用更清楚地表达意图的东西。因为你要做的是测试构造(而不是破坏)是否可以抛出,使用 new不会抛出的表达式,确切地说,然后使用 new(std::nothrow) , 或使用使用 void* 的表达式这不是一个空指针:new (std::declval<void*>()) .

这避免了由于使用 nullptr 而造成的任何混淆当您正在测试的属性与 nullptr 无关时.涉及nullptr只会让事情复杂化,让读者想知道是否使用 nullptr很重要,或者如果您只是懒惰并将其用作“一些 void* 指针值”的简写。

关于c++ - 在 decltype() 或 operator noexcept() 上下文中对 nullptr 使用 placement new,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34005426/

相关文章:

c++ - 通过getcontext和setcontext实现swapcontext

c++ - 将 reinterpret_cast 与 bool 一起使用

c++ - 删除自身内的 std::function 对象

c++11 - 当我在 Catch2 中编译 010-TestCase.cpp 文件时,获取 CATCH_SINGLE_INCLUDE : command not found Error,

c++ - 抛出 constexpr 函数

c++ - 防止使用 glibc 头文件

c++ - gcc 4.8 或更早版本是否存在关于正则表达式的问题?

c++ - CMakeLists.txt 中的编译器标志不会出现在 CMake-Gui 或 CMakeCache.txt 中

c++ - 如何获得比较两个 vector 对的子集?

c++ - 通过在共享模式下获取互斥锁来写入共享变量(而不是在独占模式下)