C++ 有没有可能写一个;“完成”;C++;使用零长度数组成员初始化?
我有一些数据类型,如果我使用普通的旧C,它将被实现为C++ 有没有可能写一个;“完成”;C++;使用零长度数组成员初始化?,c++,stl,flexible-array-member,C++,Stl,Flexible Array Member,我有一些数据类型,如果我使用普通的旧C,它将被实现为 typedef struct { ...many other members here... unsigned short _size; char _buf[0]; } my_data; 我想做的是,基本上把它变成一个类,并添加常用的操作符,如less、equality、copy构造函数、操作符赋值等等。正如您所想象的那样,我将在诸如std::map之类的关联容器中使用此类类作为其键 理想情况下
typedef struct {
...many other members here...
unsigned short _size;
char _buf[0];
} my_data;
我想做的是,基本上把它变成一个类,并添加常用的操作符,如less、equality、copy构造函数、操作符赋值等等。正如您所想象的那样,我将在诸如std::map之类的关联容器中使用此类类作为其键
理想情况下,我需要缓冲区与对象本身处于同一级别,否则当我必须比较其中两个(缓冲区)时,我会让CPU获取指针并将其加载到内存中;我不想使用std::vector,因为分配的内存不会和其余的数据成员相邻
对我来说,主要的问题是,在C语言中,我会有一个函数,给定缓冲区的大小,它会为它分配适当的内存大小。在C++中,这样的事情是不可能完成的。
我说得对吗?
干杯您可以在C++中采用这种方式:
struct MyData {
unsigned short size_;
char * buf () { return reinterpret_cast<char *>(&size_ + 1); }
//...
};
您可以在C++中以这种方式处理它:
struct MyData {
unsigned short size_;
char * buf () { return reinterpret_cast<char *>(&size_ + 1); }
//...
};
这是完全不可能的。对象的大小实际上是可变的,但是
std::map
始终将其视为固定大小,并且无法实现复制或移动。你需要一个旧的C风格的容器来使用这种破解
编辑:自定义分配器。有趣的解决方案,我没想到。我不知道你是否能让它工作,但它值得研究。这是不可能的。对象的大小实际上是可变的,但是
std::map
始终将其视为固定大小,并且无法实现复制或移动。你需要一个旧的C风格的容器来使用这种破解
编辑:自定义分配器。有趣的解决方案,我没想到。我不知道你是否能让它工作,但它值得研究。不,不可能。零长度数组不是合法的C++。 对于长度为1的数组,您可以执行非常类似的操作,但是您仍然需要自己管理实例的创建,因此不需要复制构造函数,也不需要将对象存储在
std::map
中
也许是这样的:
class my_data {
public:
static my_data* create(int size) {
void* memory = malloc(sizeof(_size) + size);
return new(memory) my_data(size);
}
static void destroy(my_data* ptr) {
ptr->~my_data();
free(ptr);
}
private:
//disable construction and destruction except by static methods above
explicit my_data(int size) : _size(size) {}
~my_data(){}
//disable copying
my_data(const my_data&);
my_data& operator=(const my_data&);
unsigned short _size;
char _buf[1];
};
请注意,默认构造函数、析构函数、复制构造函数和赋值运算符都是私有的,这大大限制了类的使用方式
1在实际应用中-它不符合标准,但几乎在任何地方都可以使用。不,这是不可能的。零长度数组不是合法的C++。 对于长度为1的数组,您可以执行非常类似的操作,但是您仍然需要自己管理实例的创建,因此不需要复制构造函数,也不需要将对象存储在
std::map
中
也许是这样的:
class my_data {
public:
static my_data* create(int size) {
void* memory = malloc(sizeof(_size) + size);
return new(memory) my_data(size);
}
static void destroy(my_data* ptr) {
ptr->~my_data();
free(ptr);
}
private:
//disable construction and destruction except by static methods above
explicit my_data(int size) : _size(size) {}
~my_data(){}
//disable copying
my_data(const my_data&);
my_data& operator=(const my_data&);
unsigned short _size;
char _buf[1];
};
请注意,默认构造函数、析构函数、复制构造函数和赋值运算符都是私有的,这大大限制了类的使用方式
1在实用术语中,它不是标准的,但它几乎在任何地方都能工作。
零数组长度数组成员在C++中是无效的,所以标题中的问题的答案是“否”。理论上-不,实际上-是的,绝对没有问题。也许你可以使用一些标准的容器代替?哦,顺便说一下,带有单个或双领先下划线的标识符由C和C++标准保留。@ Joachim Pileborg;带有单前导下划线的标识符仅在全局范围内保留(除非下划线后面的字符是大写字母)。所以,\u buf
很好。谢谢。但是,如何在运行时动态地决定数据的分配大小?您必须先创建零大小的版本,然后再进行扩展。分配和初始化是C++中的两种不同的畜牲。在分配时间,operator new
被指定为sizeof(MyData)
,以便将其传递给malloc
,但此时您无法告诉任何有关数据的信息。@Emanuele:void*p=::operator new(sizeof(MyData)+您的buf长度);MyData*d=::new(p)MyData()代码>,反正是这样的。这种方法的问题是不能使用像STL和/或智能指针之类的好功能。谢谢。但是,如何在运行时动态地决定数据的分配大小?您必须先创建零大小的版本,然后再进行扩展。分配和初始化是C++中的两种不同的畜牲。在分配时间,operator new
被指定为sizeof(MyData)
,以便将其传递给malloc
,但此时您无法告诉任何有关数据的信息。@Emanuele:void*p=::operator new(sizeof(MyData)+您的buf长度);MyData*d=::new(p)MyData()代码>,无论如何都是这样。这种方法的问题是不能使用STL和/或智能指针之类的优秀功能。感谢您的确认。我将尝试使用自定义分配器解决此问题的部分原因,和/或我可能必须编写C容器来完成此操作(如您所建议的)。自定义分配器将是一个有趣的解决方案。我没有想到这一点,但实际上我不确定它的定义是什么。它将用于解决这个问题的部分原因,和/或我可以尝试使缓冲区在每个实例的指针之后启动,以便处于相同的位置