在 decltype() 或 operator noexcept() 上下文中对 nullptr 使用 placement new
Using placement new on nullptr in decltype() or operator noexcept() context
标准允许写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 * >{});
Disabler typename = decltype(S(std::declval< T >()))
需要存在析构函数,但放置 new
不需要。
然而,decltype
和运算符 noexcept
的上下文未评估,我想知道是否符合标准。因为编译器可能会证明测试表达式 100% 不正确。
在标准的所有已发布版本中,可以将空指针传递给 placement new,编译器需要处理这种情况,因此如果代码调用带有空指针的 ::operator new(size_t, void*)
是可以的指针。
但是,class 可能会重载 operator new(size_t, nullptr_t)
,在这种情况下,您的表达式将使用它,因此您无法确切知道会发生什么(例如,它可能被删除,或者它可能是 noexcept(false)
).
在 C++17 的工作草案中,如果保留位置分配函数 returns 为 null(这在 a question I asked here and on the committee lists 引起的讨论后已更改),则为未定义行为。目前尚不清楚这是否意味着它实际上被调用并且 returns 为空,或者甚至您的用法是否未定义。
我宁愿不冒险,而是会使用更清楚地表达意图的东西。因为你要做的是测试构造(而不是破坏)是否可以抛出,通过使用不会抛出的 new
表达式,准确地说,并使用 new(std::nothrow)
,或使用表达式使用的 void*
不能证明是空指针:new (std::declval<void*>())
.
当您正在测试的 属性 与 nullptr
无关时,这可以避免因使用 nullptr
而造成的任何混淆。涉及 nullptr
只会使事情复杂化,因为 reader 想知道 nullptr
的使用是否重要,或者您是否只是懒惰并将其用作 shorthand "some void*
pointer value".
标准允许写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 * >{});
Disabler typename = decltype(S(std::declval< T >()))
需要存在析构函数,但放置 new
不需要。
然而,decltype
和运算符 noexcept
的上下文未评估,我想知道是否符合标准。因为编译器可能会证明测试表达式 100% 不正确。
在标准的所有已发布版本中,可以将空指针传递给 placement new,编译器需要处理这种情况,因此如果代码调用带有空指针的 ::operator new(size_t, void*)
是可以的指针。
但是,class 可能会重载 operator new(size_t, nullptr_t)
,在这种情况下,您的表达式将使用它,因此您无法确切知道会发生什么(例如,它可能被删除,或者它可能是 noexcept(false)
).
在 C++17 的工作草案中,如果保留位置分配函数 returns 为 null(这在 a question I asked here and on the committee lists 引起的讨论后已更改),则为未定义行为。目前尚不清楚这是否意味着它实际上被调用并且 returns 为空,或者甚至您的用法是否未定义。
我宁愿不冒险,而是会使用更清楚地表达意图的东西。因为你要做的是测试构造(而不是破坏)是否可以抛出,通过使用不会抛出的 new
表达式,准确地说,并使用 new(std::nothrow)
,或使用表达式使用的 void*
不能证明是空指针:new (std::declval<void*>())
.
当您正在测试的 属性 与 nullptr
无关时,这可以避免因使用 nullptr
而造成的任何混淆。涉及 nullptr
只会使事情复杂化,因为 reader 想知道 nullptr
的使用是否重要,或者您是否只是懒惰并将其用作 shorthand "some void*
pointer value".