标准是否允许撰写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%不相关性。
答案 0 :(得分:5)
在标准的所有已发布版本中,可以将空指针传递给placement new,并且编译器需要处理该情况,因此如果它使用空指针调用::operator new(size_t, void*)
,则代码是正常的。
然而,一个类可能会重载operator new(size_t, nullptr_t)
,在这种情况下你的表达式会使用它,因此你无法准确知道会发生什么(例如它可能被删除,或者可能是{{ 1}})。
在C ++ 17的工作草案中,如果保留的放置分配函数返回null,则它是未定义的行为(在a question I asked here and on the committee lists引起的讨论之后这已经改变)。目前尚不清楚这是否意味着它实际上被调用并返回null,或者甚至您的使用是否未定义。
我宁愿不冒险,也会使用更明确表达意图的东西。因为你要做的是测试构造(但不是破坏)是否可以抛出,使用一个不会抛出的noexcept(false)
表达式,准确地说,并使用new
,或者使用使用new(std::nothrow)
的表达式,不能证明是空指针:void*
。
当您测试的属性与new (std::declval<void*>())
无关时,这可以避免因使用nullptr
而导致的混淆。让nullptr
参与使问题复杂化,让读者想知道nullptr
的使用是否重要,或者您是否只是懒惰并将其用作&#34;某些{的简写{1}}指针值&#34;。