在decltype()或operator noexcept()上下文中使用new new on nullptr

时间:2015-11-30 18:26:30

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

标准是否允许撰写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%不相关性。

1 个答案:

答案 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;。