3

可能重复:
可以以便携式方式使用新的阵列放置吗?

我想分配对象 T 的数组并使用对象构造函数初始化对象。这很容易使用 c++ new

T * pointerT = new T [arraySize];

它将为所有arraySize对象调用 T 构造函数。但是,由于某种原因,我必须使用 Cmemalign而不是 new。在这种情况下,我最终使用以下代码

T * pointerT = (T*) memalign(64,arraySize * sizeof(T)); 
new (pointerT) T(); 

new (pointerT) T()只调用一次 T 构造函数。但是,我需要为所有对象调用 T 构造函数,而不仅仅是第一个对象。

我很感激你的帮助。

4

2 回答 2

8

循环执行new (pointerT) T()保留pointerT一个对象,其析构函数会破坏对象并调用free(例如调用它aligned_vector),并在构造函数中执行以下操作:

ptrdiff_t k = 0;

try
{
    for (; k < n; k++)
        new (pointerT + k) T();
}

catch (...)
{
    for (; k > 0; k--) (pointerT + k)->~T();
    free(pointerT);
    throw;
}

这样,如果构造失败,您可以通过事务处理而不会泄漏内存或资源。

为此,就可重用性而言,最简单的方法是实现您自己的对齐感知分配器和 use std::vector,它为您处理异常安全(和许多其他好东西)。

这是一个示例分配器,C++11,带有编译时对齐规范(请提出增强和更正建议):

template <typename T, size_t align>
struct aligned_allocator
{
    typedef T value_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;

    template <typename U>
    struct rebind { typedef aligned_allocator<U, align> other; };

    T* address(T& t) { return &t; }

    T* allocate(size_t n, const T* = 0) 
    {
        if (T* ans = memalign(align, n * sizeof(T))) return ans;
        else throw std::bad_alloc();
    }

    T* deallocate(T* p, size_t) { free(p); }

    size_t max_size() const 
    {
        return size_t(-align) / sizeof(T); 
    }

    template <typename U, typename... Args>
    void construct(U* p, Args&&... args)
    {
        ::new((void *)p U(std::forward<Args>(args)...);
    }

    template <typename U>
    void destroy(U* p) { p->~U(); }
};

示例用法:std::vector<T, aligned_allocator<T, 64>> v(42);构造一个具有对齐存储和 64 个元素的向量。

你也可以在 C++11 中做

template <typename T, size_t align>
using aligned_vector = std::vector<T, aligned_allocator<T, align>>;

你现在可以使用

aligned_vector<MyType, 64> v;

并享受异常安全、移动感知、迭代器感知、基于范围的循环感知等,具有对齐存储的向量。

于 2012-07-09T19:21:28.480 回答
3

如果T是可复制的,例如:

std::uninitialized_fill_n( pointerT, arraySize, T()); // #include <memory>

应该做的伎俩。如果在中途抛出异常,它甚至会为您处理已构造的对象的销毁。

于 2012-07-09T21:50:35.603 回答