确实用作对象封装char数组打破严格别名规则(Does encapsulated char arra

2019-09-17 23:19发布

请执行以下操作类打破严格走样规则:

template<typename T>
class store {
    char m_data[sizeof(T)];
    bool m_init;
public:
    store() : m_init(false) {}
    store(const T &t) : init(true) {
        new(m_data) T(t);
    }
    ~store() {
        if(m_init) {
            get()->~T();
        }
    }
    store &operator=(const store &s) {
        if(m_init) {
            get()->~T();
        }
        if(s.m_init) {
            new(m_data) T(*s.get());
        }
        m_init = s.m_init;
    }
    T *get() {
        if (m_init) {
            return reinterpret_cast<T *>(m_data);
        } else {
            return NULL;
        }
    }
}

我的一个标准的解读是,这是不正确,但我不知道(我的使用是有对象的数组T +这些对象的一些元数据,但有过对象的构造/解构控制,无需手动分配内存)的分配对象用作用于放置例子new的标准。

Answer 1:

该标准包含本说明:

[ 注:典型的实现将定义aligned_storage为:

 template <std::size_t Len, std::size_t Alignment> struct aligned_storage { typedef struct { alignas(Alignment) unsigned char __data[Len]; } type; }; 

- 注完 ]

-指针修改[meta.trans.ptr] 20.9.7.5/1

而aligned_storage是与部分定义的:

所述构件的typedef 类型应是适合于用作未初始化的存储对于其尺寸为至多Len和其对准是对准的除数任何对象POD类型。

通过限制在该一个对象可以被构造地址标准所涵盖的唯一属性是对准。 实现可能有一些其他的限制,但我不熟悉的任何事情。 因此,只要确保有正确的定位是足够您的实现,我想这应该没问题。 (在预C ++编译器11可以使用使用编译器扩展用于设置对准如__attribute__((alignment(X)))__declspec(align(X))

我相信,只要你不访问底层存储直接别名规则甚至不进画面,因为别名规则覆盖时,它是好的,通过不同类型的对象访问对象的值。 构建一个对象,只访问该对象不涉及通过任何其他类型的对象访问对象的价值。

此前答案

混叠规则特别允许字符数组别名其他对象。

如果一个程序试图通过的以外的以下类型的行为是未定义的一个glvalue访问对象的存储值:

[...]

- 一个char或unsigned char类型。

-左值和右值[basic.lval] 3.10 / 10

你需要确保该阵列用于T类型正确对齐虽然。

alignas(T) char m_data[sizeof(T)];

以上是C ++ 11的设置对准语法,但如果你是一个C ++编译器03,那么你就需要一个编译器特定的属性做同样的事情。 GCC有__attribute__((aligned(32)))和MSVC具有__declspec(align(32))


Kerrek SB提出了一个很好点的混叠规则指出这没关系经由字符数组访问为T对象的值,但可能并不意味着通过T对象访问字符数组的值是好的。 然而,如果放置新表达被很好地定义,然后,创建一个T类型的对象,我认为它的好访问由定义为T对象,并读取原稿char数组是访问所创建的T类型的对象的值,这是所涵盖混叠规则。

我认为这意味着你可以存储在一个T类型的对象,例如,一个int数组,只要你不通过原int数组,然后你不打不确定的行为访问该T类型的对象的值。



Answer 2:

什么是允许是采取T对象和把它解释为字符数组。 但是,它是在一般不允许参加字符的任意阵列,并且把它作为一个T ,或甚至作为指针的含有存储器的区域T 。 最起码,你的字符数组将需要正确对齐。

解决此问题的方法可能是使用一个联合:

union storage { char buf[sizeof(T)]; T dummy; };

现在,您可以构建一个Tstorage.buf

T * p = ::new (storage.buf) T();


文章来源: Does encapsulated char array used as object breaks strict aliasing rule