这是C++;结构黑客的替代方案? 是下面的C++吗?这是将可变长度尾部实现为扁平结构的另一种方法。在C中,这通常是通过 结构Str { Str(int c):计数(c){} 大小/数量; Elem*data(){return(Elem*)(this+1);} }; Str*Str=(Str*)新字符[sizeof(Str)+sizeof(Elem)*计数]; 新(str)str(计数); 对于(int i=0;idata()+i)元素(); str->data()[0]=elem0; str->data()[1]=elem1; //等等。。。
我这样问是为了回应以下问题:不,这是无效的: 元素可能与这是C++;结构黑客的替代方案? 是下面的C++吗?这是将可变长度尾部实现为扁平结构的另一种方法。在C中,这通常是通过 结构Str { Str(int c):计数(c){} 大小/数量; Elem*data(){return(Elem*)(this+1);} }; Str*Str=(Str*)新字符[sizeof(Str)+sizeof(Elem)*计数]; 新(str)str(计数); 对于(int i=0;idata()+i)元素(); str->data()[0]=elem0; str->data()[1]=elem1; //等等。。。,c++,C++,我这样问是为了回应以下问题:不,这是无效的: 元素可能与Str具有不同的对齐方式,因此(重新解释)将Str+1强制转换到Elem*可能会给您一个有效的指针,也可能不会给您一个有效的指针,而访问可能会给出未定义的行为 但毕竟,你为什么要这样做呢?在什么意义上有效?它是C++的,使用C类技术,只要项目要求没有其他选择,IMHO就很好。 如果您询问它是否会工作,只要数据对齐问题不会使代码崩溃(即非x86,如SPARC等),它就会工作。C++在处理内存时的行为类似于C。 我在gcc和VS下使用以下修改对
Str
具有不同的对齐方式,因此(重新解释)将Str+1
强制转换到Elem*
可能会给您一个有效的指针,也可能不会给您一个有效的指针,而访问可能会给出未定义的行为
但毕竟,你为什么要这样做呢?在什么意义上有效?它是C++的,使用C类技术,只要项目要求没有其他选择,IMHO就很好。 如果您询问它是否会工作,只要数据对齐问题不会使代码崩溃(即非x86,如SPARC等),它就会工作。C++在处理内存时的行为类似于C。 我在gcc和VS下使用以下修改对其进行了测试,结果表明它可以正常工作:
struct Elem
{
Elem() : x(0), t(0) { memset(c, 0, sizeof(c));}
Elem(int v) : x(v), t(0) { memset(c, 0, sizeof(c));}
Elem(const Elem &e) { *this = e; }
Elem &operator=(const Elem &e)
{
if (this != &e)
{
memcpy(c, e.c, sizeof(c));
x = e.x;
t = e.t;
}
return *this;
}
char c[21];
int x;
char t;
};
struct Str
{
Str(int c) : count(c) {}
size_t count;
Elem* data() { return (Elem*)(this + 1); }
};
int count = 11;
Str *str = (Str*)new char[sizeof(Str) + sizeof(Elem) * count];
new (str) Str(count);
for (int i = 0; i < count; ++i)
{
new (str->data() + i) Elem();
str->data()[i] = Elem(i+1);
}
for (int i=0; i<str->count; i++)
cout << "[" << i << "]: " << str->data()[i].x << endl;
结构元素
{
Elem():x(0),t(0){memset(c,0,sizeof(c));}
元素(intv):x(v),t(0){memset(c,0,sizeof(c));}
Elem(const Elem&e){*this=e;}
电气和操作员=(常量电气和电气)
{
如果(此!=&e)
{
memcpy(c、e.c、sizeof(c));
x=e.x;
t=e.t;
}
归还*这个;
}
charc[21];
int x;
查尔特;
};
结构Str
{
Str(int c):计数(c){}
大小/数量;
Elem*data(){return(Elem*)(this+1);}
};
整数计数=11;
Str*Str=(Str*)新字符[sizeof(Str)+sizeof(Elem)*计数];
新(str)str(计数);
对于(int i=0;i如果
Elem
与Str
具有不同的对齐方式,我想这是行不通的。这很容易解决:union{size\u t count,Elem dummy;}
如果你真的想做得漂亮,可以使用模板元编程来使dummy
成为Elem
和std::max\u align\t
中较小的一个。这可能行得通。问题是为什么你会在C++中做这种事情。有更好的方法来编写动态同构指针容器。为什么?低级黑客。但这似乎是一个问题,谢谢。通常的原因是引用的位置。另请参见std::make_shared
。此外,IIRCnew char[]
适合所有类型(能够作为malloc
的替代品)@MSalters:new char[]
适合对齐,但在偏移Str
后,所有下注都被取消。@MatthieuM。的确,但我的话是关于第一颗子弹的。这就是声称new[]
没有返回合适的对齐内存的方法。问题在于尾随数组。(正如我所评论的,这种对齐方式是固定的)@MSalters:实际上,newchar[]
可能并没有针对所有类型正确对齐newchar[]
仅保证对所有标准类型进行正确对齐,即达到alignof(std::max_align_t)
。虽然这取代了所有可能作为这些类型组合创建的类型,但有一些特定的向量类型用于SSE/AVX指令,例如可能有更严格的对齐要求(通过编译器内部函数指定),这些不在本保证范围内。当然,在这种情况下,它应该适用于Str
。
struct Elem
{
Elem() : x(0), t(0) { memset(c, 0, sizeof(c));}
Elem(int v) : x(v), t(0) { memset(c, 0, sizeof(c));}
Elem(const Elem &e) { *this = e; }
Elem &operator=(const Elem &e)
{
if (this != &e)
{
memcpy(c, e.c, sizeof(c));
x = e.x;
t = e.t;
}
return *this;
}
char c[21];
int x;
char t;
};
struct Str
{
Str(int c) : count(c) {}
size_t count;
Elem* data() { return (Elem*)(this + 1); }
};
int count = 11;
Str *str = (Str*)new char[sizeof(Str) + sizeof(Elem) * count];
new (str) Str(count);
for (int i = 0; i < count; ++i)
{
new (str->data() + i) Elem();
str->data()[i] = Elem(i+1);
}
for (int i=0; i<str->count; i++)
cout << "[" << i << "]: " << str->data()[i].x << endl;