我知道我可以new char[n]
创建一个n
个字符数组。即使n
不是编译时常量,这也适用。
但是我想说我想要一个大小变量,然后是n个字符:
我对此的第一次尝试如下:
struct Test
{
std::size_t size;
char a[];
};
但似乎new Test[n]
没有达到我的预期,而是分配n
size
s。
我还发现sizeof(std::string)
在ideone处是4,因此它似乎可以在一个块中分配size和char数组。
有没有办法实现我所描述的(大概是std::string
已经做过的事情)?
答案 0 :(得分:11)
虽然可以执行此操作(并且它经常在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));
C99之前的C规范不允许结构中的零长度数组。要解决此问题,将创建一个包含单个元素的数组,并将一个小于所请求元素数的数组添加到实际结构的大小(大小和第一个元素)以创建预期大小。
答案 1 :(得分:9)
您可以使用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();
}
答案 2 :(得分:7)
您还可以使用“长度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也支持“0长度”数组,正是出于这个目的: http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
答案 3 :(得分:2)
如果我理解正确,你需要一个存储指向动态分配的长度前缀字符串的指针的类。你可以利用char*
可以安全地别名的事实来做到这一点。
一个简单的实现,只是为了展示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);
}
};
答案 4 :(得分:1)
让我们使用std::vector
在C ++中保持简短和甜蜜。
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);