注意
[unique.ptr]不能保证
std::unique_ptr
是标准的,但是人们期望它包含一个单个T*
,从本质上讲,它可以保证它是
这是一个已知的问题,归结为GCC错误104419
或LLVM问题53021。 我们可以将其作为GCC错误写出,因为GCC在这里不合规。 简而
std::unique_ptr
std::tuple
的情况下),并且template <typename T, typename Deleter = empty>
struct unique_ptr {
private:
tuple<T*, Deleter> data;
};
用于避免浪费在空类上的任何字节。
从历史上看,这是通过依靠EBO(空基础优化),
但是由于使用libstdc ++ 11,因此使用了std::deleter
会产生一些实施差异。
there是一个最小的复制品,取自Jonathan Wakely的错误报告,并进行了稍作调整(
Https://godbolt.org/z/xke4r7h71):
std::tuple
只有clang失败了标记的断言,GCC都通过了所有的主张。 删除
[[no_unique_address]]
使两个编译器的断言失败。
哪个编译器是正确的
这是GCC错误。 从本质上讲,
#include <type_traits>
template<typename T, bool = __is_empty(T)> struct node;
template<typename T> struct node<T, true>
{
[[no_unique_address]] T t;
};
template<typename T> struct node<T, false>
{
T t;
};
template<typename... T> struct tuple;
template<typename T>
struct tuple<T> : node<T> { };
template<typename T, typename U>
struct tuple<T, U> : tuple<U>, node<T>
{ };
struct empty {};
static_assert( sizeof(tuple<int, empty>) == sizeof(int), "" );
static_assert( __is_standard_layout(tuple<int>), "");
static_assert( __is_standard_layout(tuple<empty>), "");
static_assert( __is_standard_layout(tuple<int, empty>), ""); // Clang fails
template <typename T, typename Deleter = empty>
struct unique_ptr {
tuple<T*, Deleter> data;
};
static_assert( __is_standard_layout(tuple<int, empty>)); // Clang fails
static_assert( __is_standard_layout(unique_ptr<int>)); // Clang fails
不应该对类别是否是标准的标准层有任何影响,但GCC认为,使用此属性“删除”一个子对象会绕过[class.prop]段2.6段::
[如果该类是标准级别,则在同一班级中首先在同一类中声明的所有非静态数据成员和基础类别,并且[...]
A
// Clang fails
将在不同的基类中首先声明数据成员,这通常会使一类失去标准级别的资格。