C++ 分配具有可变长度数组成员的结构
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7641698/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Allocating struct with variable length array member
提问by Clinton
I know I can do new char[n]
to create an array of n
chars. This works even when n
is not a compile time constant.
我知道我可以new char[n]
创建一个n
字符数组。即使n
不是编译时常量,这也有效。
But lets say I wanted a size variable followed by n chars:
但是可以说我想要一个大小变量,后跟 n 个字符:
My first attempt at this is the following:
我的第一次尝试如下:
struct Test
{
std::size_t size;
char a[];
};
However it seems new Test[n]
doesn't do what I expect, and instead allocates n
size
s.
但是,它似乎new Test[n]
没有按照我的预期进行,而是分配了n
size
s。
I've also found that sizeof(std::string)
is 4 at ideone, so it seems it can allocate both the size and the char array in one block.
我还发现sizeof(std::string)
ideone 是 4,所以它似乎可以在一个块中分配大小和字符数组。
Is there a way I can achieve what I described (presumably what std::string
already does)?
有没有办法可以实现我所描述的(大概std::string
已经做了什么)?
回答by Adam Maras
While you cando this (and it was often used in C as a workaround of sorts) it's not recommended to do so. However, if that's reallywhat you want to do... here's a way to do it with most compilers (including those that don't play nicely with C99 enhancements).
虽然您可以这样做(并且它经常在 C 中用作各种解决方法),但不建议这样做。但是,如果这真的是您想要做的……这里有一种方法可以使用大多数编译器(包括那些不能很好地与 C99 增强配合使用的编译器)。
#define TEST_SIZE(x) (sizeof(Test) + (sizeof(char) * ((x) - 1)))
typedef struct tagTest
{
size_t size;
char a[1];
} Test;
int elements = 10; // or however many elements you want
Test *myTest = (Test *)malloc(TEST_SIZE(elements));
The C specifications prior to C99 do not allow a zero-length array within a structure. To work around this, an array with a single element is created, and one less than the requested element count is added to the size of the actual structure (the size and the first element) to create the intended size.
C99 之前的 C 规范不允许在结构中使用零长度数组。为了解决这个问题,创建了一个具有单个元素的数组,并将比请求的元素计数少的一个添加到实际结构的大小(大小和第一个元素)以创建预期的大小。
回答by Miguel
You can use placement new
:
您可以使用placement new
:
#include <new>
struct Test {
size_t size;
char a[1];
static Test* create(size_t size)
{
char* buf = new char[sizeof(Test) + size - 1];
return ::new (buf) Test(size);
}
Test(size_t s) : size(s)
{
}
void destroy()
{
delete[] (char*)this;
}
};
int main(int argc, char* argv[]) {
Test* t = Test::create(23);
// do whatever you want with t
t->destroy();
}
回答by Yann Ramin
You can also use the "Length 1 Array" trick. This is in C:
您还可以使用“长度 1 数组”技巧。这是在 C 中:
struct Test {
size_t size;
char a[1];
}
int want_len = 2039;
struct Test *test = malloc(sizeof(struct Test) + (want_len - 1));
test->size = want_len;
GCC also supports "0 length" arrays for exactly this purpose: http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
GCC 也支持“0 长度”数组正是为了这个目的:http: //gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
回答by R. Martinho Fernandes
If I understand correctly, you want a class that stores a single pointer to a dynamically allocated length-prefixed string. You can do that by taking advantage of the fact that char*
can safely alias anything.
如果我理解正确,您需要一个类来存储指向动态分配的长度前缀字符串的单个指针。您可以利用char*
可以安全地别名任何东西的事实来做到这一点。
A simplistic implementation, just to show how it can be done:
class LPS
{
private:
char* ptr;
public:
LPS() noexcept : ptr(nullptr) {} // empty string without allocation
explicit LPS(std::size_t len) {
// Allocate everything in one go
// new[] gives storage aligned for objects of the requested size or less
ptr = new char[sizeof(std::size_t) + len];
// Alias as size_t
// This is fine because size_t and char have standard layout
*reinterpret_cast<std::size_t*>(ptr) = len;
}
explicit LPS(char const* sz) {
std::size_t len = std::char_traits<char>::length(sz);
ptr = new char[sizeof(std::size_t) + len;
*reinterpret_cast<std::size_t*>(ptr) = len;
std::copy(sz, sz + len, ptr + sizeof(std::size_t));
}
LPS(LPS const& that) {
if(that.ptr) {
ptr = new char[sizeof(std::size_t) + that.size()];
std::copy(that.ptr, that.ptr + sizeof(std::size_t) + that.size(), ptr);
} else ptr = nullptr;
}
LPS(LPS&& that) noexcept {
ptr = that.ptr;
that.ptr = nullptr;
}
LPS& operator=(LPS that) {
swap(that);
return *this;
}
~LPS() noexcept {
// deleting a null pointer is harmless, no need to check
delete ptr;
}
void swap(LPS& that) noexcept {
std::swap(ptr, that.ptr);
}
std::size_t size() const noexcept {
if(!ptr) return 0;
return *reinterpret_cast<std::size_t const*>(ptr);
}
char* string() noexcept {
if(!ptr) return nullptr;
// the real string starts after the size prefix
return ptr + sizeof(std::size_t);
}
};
回答by Mahesh
Let's keep things short and sweet in C++ using std::vector
.
让我们在 C++ 中使用std::vector
.
struct Test
{
std::size_t size;
char *a; // Modified to pointer
Test( int size ): size(size), a(new char[size+1])
{}
};
std::vector<Test> objects(numberOfObjectsRequired,argumentToTheConstructor);