标准是否允许写decltype(::new (nullptr) T(std::declval< Args >()...))
或 noexcept(::new (nullptr) T(std::declval< Args >()...))
?特别感兴趣的安置new
在 nullptr
正确性。考虑以下代码:
#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/