C++ 将sizeof和placement new相结合是否安全?

C++ 将sizeof和placement new相结合是否安全?,c++,templates,c++11,placement-new,C++,Templates,C++11,Placement New,考虑以下类别: template <class T> class defer { public: template <class ...Args> void construct(Args&&...); T& obj(); ~defer(); private: std::uint8_t memory[sizeof(T)]; T * ptr(); }; template <class T>

考虑以下类别:

template <class T>
class defer {
public:
    template <class ...Args>
    void construct(Args&&...);
    T& obj();
    ~defer();
private:
    std::uint8_t memory[sizeof(T)];
    T * ptr();
};

template <class T>
template <class ...Args>
void defer<T>::construct(Args&& ...args) {
    new(static_cast<void*>(&memory[0])) T(std::forward<Args>(args)...);
}

template <class T>
T& defer<T>::obj() {
    return *(ptr());
}

template <class T>
defer<T>::~defer() {
    ptr()->~T();
}

template <class T>
T * defer<T>::ptr() {
    return static_cast<T*>(&memory[0]);
}
模板
班级延迟{
公众:
模板
无效构造(参数和…);
T&obj();
~defer();
私人:
std::uint8_t内存[sizeof(t)];
T*ptr();
};
模板
模板
void defer::construct(Args&&…Args){
新的(静态_转换(&内存[0])T(标准::转发(args)…);
}
模板
T&defer::obj(){
返回*(ptr());
}
模板
延迟::~defer(){
ptr()->~T();
}
模板
T*defer::ptr(){
返回静态_强制转换(&内存[0]);
}
现在我知道这有一些问题,但是为了使代码简短以便于讨论,我们将假设在对象超出范围之前总是调用defer::construct()


也就是说,这样做一定安全吗?或者,在多重虚拟继承和其他疯狂的奇怪情况下,std::uint8_t[sizeof(t)]是否可以分配足够的空间

R.马丁尼奥·费尔南德斯击败了我!使用

typename std::aligned_storage<sizeof(T)>::type  memory;
typename std::aligned_storage::type memory;
你可以走了。有关详细信息,请参阅


正如我们的评论员小组所指出的,默认对齐总是足够的,但可能比您的类型所需的更严格(因此您会用额外的填充浪费空间)。您可以通过显式指定来避免这种情况:

typename std::aligned_storage<sizeof(T), alignof(T)>::type memory;
typename std::aligned_storage::type memory;

std::uint8\u t[sizeof(t)]
将始终有足够的空间。但是它可能并不总是具有正确的对齐方式(
std::aligned_storage
可以在这方面提供帮助)。
uint8_t
是可选的。使用
uint_-least8_-t
uint_-fast8_-t
;它们将永远存在。@Pete Becker:是的,但是你知道有没有没有没有8位整数类型的平台?此外,我知道在某些平台上,出于效率目的,uint_least8_t和uint_fast8_t都是typedef到int,这可能意味着300%的内存开销
std::uint8_least8_t[sizeof(t)/sizeof(std::uint_least8_t)+((sizeof(t)%sizeof(std::uint_least8_t)!=0)?1:0)]
工作正常,但对我来说有点难看……
uint_least8_t
必须是至少有8位的无符号类型的同义词,“这样大小较小的无符号类型至少没有指定宽度”。(C标准,7.20.1.2/2)。如果您的实现在有较小类型可用时将其定义为
int
,则它不仅具有错误的属性(因为它是有符号的类型),而且它太大,因此不符合标准。对于非8位系统,请参阅。哈哈,有那么一会儿,你犯了一个常见的错误,忘记了
::键入
:p关于
对齐的存储
?没有什么大不了的,但是在<>代码> t//>不需要缺省(最大)对齐的情况下,可以节省填充。默认对齐是“对于任何大小不大于”长度的C++对象类型的最严格的对齐要求。与分配
char
数组时的对齐要求类似。在某些情况下,您不需要如此严格的对齐;e、 g.如果T是int[2],则只需要对int进行对齐,但默认对齐方式对于任何两倍于该大小的对象都足够。Cheers-修复了对齐描述。
aligned_存储
可能已经在内部使用它,因此不清楚您是否获得了任何东西,但它应该可以工作。