C++ C++;创建具有可变项目数的结构的方法
我需要创建一个内存区域,其末尾的项目数量可变。我可以这样写:C++ C++;创建具有可变项目数的结构的方法,c++,c++11,C++,C++11,我需要创建一个内存区域,其末尾的项目数量可变。我可以这样写: #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= (MyDa
#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;
}
此代码在VS 2015上运行,并警告大小为零的数组不是标准数组
一点搜索显示我是C黑客,C++不支持。
我如何在C++中做到这一点呢?它适用于一般可复制的类型:
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;
}
模板
类压缩数组{
公众:
压缩数组(整数大小){
buf=新字符[sizeof(INT)+size*sizeof(T)];
memcpy(buf_u3;和size,sizeof(INT));
}
~packed_array(){delete[]buf_;}
无效集(整数索引,T值){
memcpy(buf_+sizeof(INT)+index*sizeof(T),&val,sizeof(T));
}
T获取(整数索引)常量{
温度;
memcpy(&temp,buf_+sizeof(INT)+index*sizeof(T),sizeof(T));
返回温度;
}
const char*data()const{return buf_;}
私人:
char*buf_;
静态断言(std::是可复制的::值);
};
int main(){
int n;
标准:cin>>n;
压缩_阵列a(n);
对于(int i=0;i模板
结构变量数组在数组末尾{
末端变量数组(标准::大小){
::新((void*)数据())标准::对齐存储;
对于(标准::大小\u t i=0;i0?(无符号)计数:0),
noOfItems(计数)
{}
结构清理{
void运算符()(MyData*ptr){
char*buff=重新解释(ptr);
ptr->~MyData();
删除[]buff;
}
};
公众:
使用up=std::unique\u ptr;
静态向上创建(整数计数){
如果(计数<0)计数=0;
std::unique\u ptr buff=std::make_unique(sizeof(MyData)+sizeof(int)*计数);
auto*ptr=::new((void*)buff.get())MyData(count);
(void)buff.release();
返回(ptr,{});
}
国际noOfItems;
};
MyData*getData(整数大小)
{
return MyData::create(size).release();//危险的非托管内存
}
我相信这是符合标准的,假设您的实现没有在普通类型的数组(比如char)上添加填充。我不知道thta会做什么
我没有假设MyData
只包含普通的旧数据;您可以用上面的方法将std::vector
塞进其中。我可能可以用这个假设简化几行
这不仅仅是一点痛苦
auto foo=MyData::create(100)
为MyData
创建一个唯一的ptr,该ptr后面有一个100int
s的缓冲区。(*foo)[77]
访问缓冲区的第77个元素
由于标准中的一个缺陷,在
MyData
之后没有数组,而是在相邻的内存位置有一个包含100个不同int
对象的缓冲区。这两个对象之间有很多令人讨厌的差异;naive指针算术保证在数组中工作,但在压缩的相邻之间不工作>int
s在缓冲区中。我不知道编译器会强制执行这种差异。我认为它不符合标准。你可以将某种类型的指针重新解释为不同类型的指针,但取消对此类指针的引用将是未定义的行为。例如,请参见@DanielLangr Which reinterpreet,确切地说,你是ta吗闲逛?我对它们中的大多数都很确定。你可以在char*
上做指针运算,即使那里没有任何char
s。如果你看一下构造函数,就会发现有一个MyData
和一堆int
s被塞进一个连续的缓冲区,就像我在MyD中使用placementnew
创建它们一样ata::create
。我唯一怀疑的是cleanup
中的一个,在那里我销毁MyData
对象,然后将char
数组馈送到delete[]
——我认为char[]
数组可以在我创建其他对象时保持不变,但我可能错了。嗯,可能是auto*ptr=::new((void*)buff.get())MyData(计数)
访问MyData::MyData
中的buff
的其余部分可能会有问题。这取决于MyData::MyData
中的这个指针是否可以与传递到placement-new
的无效*
指针互换。我明白了,我有点迷失在你的代码中,这相当复杂。为什么不呢您只需分配一个普通字符缓冲区,然后使用placement new来构造元素?唯一需要注意的是正确的对齐(以及异常安全)。然后您就可以通过显式析构函数调用(与std::vector
的方式相同)来销毁元素@DanielLangr我确实分配了一个纯字符缓冲区——在create
中。然后我将newMyData
放置在该缓冲区中。然后它继续在其后面放置新的元素。我想我可以在create
中创建这些元素,而不是在var_数组
中;我试图将更多的代码移到paren中T类处理这些细节,但不是很成功,因为 MyDATA//C>仍然很复杂。因为C本质上是C++的子集,所以在低级C++中经常使用C语言习惯用法,尤其是在几乎所有CPU平台上都存在的GCC/G++。
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
}