[英]C++ way of creating a structure with variable number of items
I need to create a memory region with variable number of items at the end. 我需要在末尾创建一个包含可变数量项的内存区域。 Something that I can write like this: 我可以这样写的东西:
#pragma pack(push,0)
struct MyData
{
int noOfItems;
int buffer[0];
};
#pragma pack(pop)
MyData * getData(int size)
{
bufferSize = size* sizeof(int) + sizeof(MyData ::noOfItems);
MyData * myData= (MyData *)new char[m_bufferSize];
return myData;
}
This code works on VS 2015 with a warning that array of size of zero is not standard 此代码适用于VS 2015,警告大小为零的数组不是标准的
A bit of search showed me that this is a C hack and is not supported on C++. 一些搜索向我显示这是一个C hack并且在C ++上不受支持。
What happens if I define a 0-size array in C/C++? 如果我在C / C ++中定义0大小的数组会发生什么? . 。
How can I do this in C++ 我怎么能用C ++做到这一点
What about something like this? 这样的事情怎么样? It works for trivially copyable types: 它适用于简单的可复制类型:
template <typename T, typename INT = size_t>
class packed_array {
public:
packed_array(INT size) {
buf_ = new char[sizeof(INT) + size * sizeof(T)];
memcpy(buf_, &size, sizeof(INT));
}
~packed_array() { delete[] buf_; }
void set(INT index, T val) {
memcpy(buf_ + sizeof(INT) + index * sizeof(T), &val, sizeof(T));
}
T get(INT index) const {
T temp;
memcpy(&temp, buf_ + sizeof(INT) + index * sizeof(T), sizeof(T));
return temp;
}
const char* data() const { return buf_; }
private:
char* buf_;
static_assert(std::is_trivially_copyable<T>::value);
};
int main() {
int n;
std::cin >> n;
packed_array<double, int> a(n);
for (int i = 0; i < n; i++)
a.set(i, pow(2.0, i));
for (int i = 0; i < n; i++)
std::cout << a.get(i) << std::endl;
}
Live demo: https://wandbox.org/permlink/Vc4ok756R1Sxieoj 现场演示: https : //wandbox.org/permlink/Vc4ok756R1Sxieoj
template<class T, class D>
struct var_array_at_end {
var_array_at_end( std::size_t N ) {
::new( (void*)data() ) std::aligned_storage_t<sizeof(T)*N, alignof(T)>;
for (std::size_t i = 0; i < N; ++i) {
::new( (void*)( data()+sizeof(T)*i) ) ) T();
}
}
char* data() { return reinterpret_cast<char*>(this)+sizeof(D); }
char const* data() const { return reinterpret_cast<char*>(this)+sizeof(D); }
T* ptr(std::size_t i = 0) { return reinterpret_cast<T*>( data()+sizeof(T)*i ); }
T const* ptr(std::size_t i = 0) const { return reinterpret_cast<T*>( data()+sizeof(T)*i ); }
T& operator[](std::size_t n) {
return *ptr(n);
}
T const& operator[](std::size_t n) const {
return *ptr(n);
}
};
struct MyData:
var_array_at_end<int, MyData>
{
private:
explicit MyData( int count ):
var_array_at_end<int, MyData>( count>0?(unsigned)count:0 ),
noOfItems(count)
{}
struct cleanup {
void operator()(MyData* ptr) {
char* buff = reinterpret_cast<char*>(ptr);
ptr->~MyData();
delete[] buff;
}
};
public:
using up = std::unique_ptr<MyData*, cleanup>;
static up create( int count ) {
if (count < 0) count = 0;
std::unique_ptr<char> buff = std::make_unique<char[]>( sizeof(MyData)+sizeof(int)*count );
auto* ptr = ::new( (void*)buff.get() ) MyData( count );
(void)buff.release();
return up( ptr, {} );
}
int noOfItems;
};
MyData * getData(int size)
{
return MyData::create(size).release(); // dangerous, unmanaged memory
}
I believe this is standard compliant, assuming your implementation doesn't add padding on arrays of trivial types (like char). 我相信这是标准兼容的,假设你的实现没有在普通类型的数组(如char)上添加填充。 I am unware of any implementation thta does. 我不知道任何实现。
I didn't assume that MyData
only contains plain old data; 我没想到MyData
只包含普通的旧数据; you could stuff a std::vector
into it with the above. 你可以用上面的东西把std::vector
填充到它里面。 I might be able to simplify a few lines with that assumption. 我可以用这个假设简化几行。
It is more than a bit of a pain. 这不仅仅是一种痛苦。
auto foo = MyData::create(100)
creates a unique ptr to MyData
that has a buffer of 100 int
s after it. auto foo = MyData::create(100)
为MyData
创建一个唯一的ptr,它后面有一个100 int
的缓冲区。 (*foo)[77]
accesses the 77th element of the buffer. (*foo)[77]
访问缓冲区的第77个元素。
Due to a defect in the standard, you there isn't an array after MyData
but rather a buffer containing 100 distinct int
objects in adjacent memory locations. 由于标准中存在缺陷,因此在MyData
之后没有数组,而是在相邻内存位置包含100个不同int
对象的缓冲区。 There are vrey annoying differences between those two things; 这两件事之间存在着令人烦恼的差异; naive pointer arithimetic is guaranteed to work within arrays, but not between packed adjacent int
s in a buffer. naive指针arithimetic保证在数组内工作,但不能在缓冲区中的压缩邻居int
之间工作。 I am unaware of a compiler that enforces that difference. 我不知道强制执行这种差异的编译器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.