unique_ptr 的零大小
unique_ptr's of zero size
我经常使用多维数组,我不是 std::vector
的忠实粉丝,因为无法实例化 std::vector
或 std::vector
std::vector
在不复制基础数据的情况下使用引用。
对于一维数组,我使用如下
template<typename T>
using deleted_aligned_array = std::unique_ptr<T[], std::function<void(T*)> >;
template<typename T>
deleted_aligned_array<T> deleted_aligned_array_create(size_t n) {
return deleted_aligned_array<T>((T*)_mm_malloc(n*sizeof(T),16), [](T* f)->void { _mm_free(f);});
}
这非常方便,允许我实例化一个动态大小的数组,它也适用于大小为零的数组。此外,我可以使用 std::forward
来传递数据而无需复制。
对于二维数组,我想做这样的事情
template<typename T>
using deleted_aligned_array2 = std::unique_ptr<T*,std::function<void(T**)>>;
template<typename T>
deleted_aligned_array2<T> deleted_aligned_array_create(size_t m, size_t n) {
auto arr = deleted_aligned_array2(new T*[m](), [&](T** x) {
if (malloc_usable_size(x) > 0) {
_mm_free(&(x[0][0]));
}
delete[] x;});
if (m*n > 0) {
arr.get()[0] = (T*) _mm_malloc(m*n*sizeof(T),16);
// Row pointers
for (size_t iRow = 1; iRow < m; iRow++) {
(m_data.get())[iRow] = &(m_data.get()[0][iRow*n]);
}
}
return arr;
}
它适用于零大小数组,但由于明显的原因,我从 valgrind
收到错误,invalid read of size 8
。
是否有可能以一种优雅的方式解决这个问题,而无需创建一个完整的 class 保留一个 std::unique_ptr
成员,我在其中实现移动构造函数、移动赋值等。最终,我会喜欢将其概括为用于任何维度
template<typename T, size_t Dim>
deleted_aligned_array<T,D> deleted_aligned_array_create(...);
returned 数组应该是具有递归初始化的行指针的唯一指针,它应该支持零大小数组,例如
auto arr = deleted_aligned_array_create<float,3>(4,5,10);
应该return一个带有行和列指针的 3 维数组。
问题:
1)避免以简单的方式读取无效数据。
2) 使用模板参数 D
生成类型:T*
、T**
并简单地传递 D
以递归生成行指针的代码(我已经有了)。
3)最好以便携的方式。 malloc_usable_size
是 GNU 扩展,当大小为 0 时,在 x
上调用它会导致无效读取。
提前致谢
我找到了一个解决方案,但不是很优雅。如果您有更优雅的解决方案,请 post 您的答案。一旦我们达到更高的维度,这里的解决方案就非常难看。
template <class T, size_t D>
class deleted_aligned_multi_array {
};
template <class T>
class deleted_aligned_multi_array<T,1> : public std::unique_ptr<T[], std::function<void(T*)> > {
deleted_aligned_multi_array(size_t n) :
std::unique_ptr<T[], std::function<void(T*)> >((T*)_mm_malloc(n*sizeof(T),16),
[](T* f)->void { _mm_free(f);}) {}
};
template <class T>
class deleted_aligned_multi_array<T,2> {
public:
typedef T** pointer;
typedef std::unique_ptr<T*, std::function<void(T**)>> deleted_unique_array;
deleted_aligned_multi_array() : m(0), n(0), data() {}
deleted_aligned_multi_array(size_t m, size_t n) : m(m), n(n) {
if (m*n > 0) {
data = deleted_unique_array(new T*[m](),
[&](T** x) {
if (sps::msize(x) > 0) {
_mm_free(&(x[0][0]));
}
delete[] x;});
data.get()[0] = (T*) _mm_malloc(m*n*sizeof(T),16);
for (size_t iRow = 1; iRow < m; iRow++) {
(data.get())[iRow] = &(data.get()[0][iRow*n]);
}
}
else {
data.reset();
}
}
deleted_aligned_multi_array(deleted_aligned_multi_array&& other) : m(other.m), n(other.n),
data(std::move(other.data)) {}
deleted_aligned_multi_array& operator=( deleted_aligned_multi_array&& other ) {
if (this != &other) {
data = std::move( other.data );
m = other.m;
m = other.n;
}
return *this;
}
T& operator()(size_t i, size_t j) {
return this->data.get()[0][i*n + j];
}
T* operator[](size_t m) {
return &(data.get()[m][0]);
}
const T* operator[](size_t m) const {
return data.get()[m];
}
pointer get() const {
return data.get();
}
void reset(pointer __p = pointer()) {
data.reset(__p);
}
template<typename _Up>
void reset(_Up) = delete;
private:
deleted_aligned_multi_array(const deleted_aligned_multi_array& other) = delete;
deleted_aligned_multi_array& operator=( const deleted_aligned_multi_array& a ) = delete;
public:
size_t m; ///<Number of rows
size_t n; ///<Number of columns
deleted_unique_array data; ///<Data
};
访问子数组的实用函数,现在可以轻松实现
template <class T>
std::unique_ptr<T*, std::function<void(T*)> sub_array(size_t m, size_t n, size_t i, size_t j) {
// Establish row pointers with reference i and j and dimension mxn.
}
我经常使用多维数组,我不是 std::vector
的忠实粉丝,因为无法实例化 std::vector
或 std::vector
std::vector
在不复制基础数据的情况下使用引用。
对于一维数组,我使用如下
template<typename T>
using deleted_aligned_array = std::unique_ptr<T[], std::function<void(T*)> >;
template<typename T>
deleted_aligned_array<T> deleted_aligned_array_create(size_t n) {
return deleted_aligned_array<T>((T*)_mm_malloc(n*sizeof(T),16), [](T* f)->void { _mm_free(f);});
}
这非常方便,允许我实例化一个动态大小的数组,它也适用于大小为零的数组。此外,我可以使用 std::forward
来传递数据而无需复制。
对于二维数组,我想做这样的事情
template<typename T>
using deleted_aligned_array2 = std::unique_ptr<T*,std::function<void(T**)>>;
template<typename T>
deleted_aligned_array2<T> deleted_aligned_array_create(size_t m, size_t n) {
auto arr = deleted_aligned_array2(new T*[m](), [&](T** x) {
if (malloc_usable_size(x) > 0) {
_mm_free(&(x[0][0]));
}
delete[] x;});
if (m*n > 0) {
arr.get()[0] = (T*) _mm_malloc(m*n*sizeof(T),16);
// Row pointers
for (size_t iRow = 1; iRow < m; iRow++) {
(m_data.get())[iRow] = &(m_data.get()[0][iRow*n]);
}
}
return arr;
}
它适用于零大小数组,但由于明显的原因,我从 valgrind
收到错误,invalid read of size 8
。
是否有可能以一种优雅的方式解决这个问题,而无需创建一个完整的 class 保留一个 std::unique_ptr
成员,我在其中实现移动构造函数、移动赋值等。最终,我会喜欢将其概括为用于任何维度
template<typename T, size_t Dim>
deleted_aligned_array<T,D> deleted_aligned_array_create(...);
returned 数组应该是具有递归初始化的行指针的唯一指针,它应该支持零大小数组,例如
auto arr = deleted_aligned_array_create<float,3>(4,5,10);
应该return一个带有行和列指针的 3 维数组。
问题:
1)避免以简单的方式读取无效数据。
2) 使用模板参数 D
生成类型:T*
、T**
并简单地传递 D
以递归生成行指针的代码(我已经有了)。
3)最好以便携的方式。 malloc_usable_size
是 GNU 扩展,当大小为 0 时,在 x
上调用它会导致无效读取。
提前致谢
我找到了一个解决方案,但不是很优雅。如果您有更优雅的解决方案,请 post 您的答案。一旦我们达到更高的维度,这里的解决方案就非常难看。
template <class T, size_t D>
class deleted_aligned_multi_array {
};
template <class T>
class deleted_aligned_multi_array<T,1> : public std::unique_ptr<T[], std::function<void(T*)> > {
deleted_aligned_multi_array(size_t n) :
std::unique_ptr<T[], std::function<void(T*)> >((T*)_mm_malloc(n*sizeof(T),16),
[](T* f)->void { _mm_free(f);}) {}
};
template <class T>
class deleted_aligned_multi_array<T,2> {
public:
typedef T** pointer;
typedef std::unique_ptr<T*, std::function<void(T**)>> deleted_unique_array;
deleted_aligned_multi_array() : m(0), n(0), data() {}
deleted_aligned_multi_array(size_t m, size_t n) : m(m), n(n) {
if (m*n > 0) {
data = deleted_unique_array(new T*[m](),
[&](T** x) {
if (sps::msize(x) > 0) {
_mm_free(&(x[0][0]));
}
delete[] x;});
data.get()[0] = (T*) _mm_malloc(m*n*sizeof(T),16);
for (size_t iRow = 1; iRow < m; iRow++) {
(data.get())[iRow] = &(data.get()[0][iRow*n]);
}
}
else {
data.reset();
}
}
deleted_aligned_multi_array(deleted_aligned_multi_array&& other) : m(other.m), n(other.n),
data(std::move(other.data)) {}
deleted_aligned_multi_array& operator=( deleted_aligned_multi_array&& other ) {
if (this != &other) {
data = std::move( other.data );
m = other.m;
m = other.n;
}
return *this;
}
T& operator()(size_t i, size_t j) {
return this->data.get()[0][i*n + j];
}
T* operator[](size_t m) {
return &(data.get()[m][0]);
}
const T* operator[](size_t m) const {
return data.get()[m];
}
pointer get() const {
return data.get();
}
void reset(pointer __p = pointer()) {
data.reset(__p);
}
template<typename _Up>
void reset(_Up) = delete;
private:
deleted_aligned_multi_array(const deleted_aligned_multi_array& other) = delete;
deleted_aligned_multi_array& operator=( const deleted_aligned_multi_array& a ) = delete;
public:
size_t m; ///<Number of rows
size_t n; ///<Number of columns
deleted_unique_array data; ///<Data
};
访问子数组的实用函数,现在可以轻松实现
template <class T>
std::unique_ptr<T*, std::function<void(T*)> sub_array(size_t m, size_t n, size_t i, size_t j) {
// Establish row pointers with reference i and j and dimension mxn.
}