我有一个包含几个数组的类,其大小可以通过其构造函数的参数来确定。我的问题是这个类的实例的大小无法在编译时确定,我不知道如何在运行时告诉 new 方法我需要多大的对象是。每个对象都是固定大小的,但不同的实例可能有不同的大小。
有几种解决问题的方法:
- 使用工厂
- 使用放置构造函数
- 在构造函数中分配数组并在我的对象中存储指向它们的指针。
我正在使用 C 编写的旧应用程序调整一些遗留代码。在原始代码中,程序计算出整个对象需要多少内存,为该数量调用malloc()
,然后继续初始化各个字段。
对于C ++版本,我希望能够为我的对象创建一个(相当)正常的构造函数。它将是父类的后代,并且一些代码将依赖于多态来调用正确的方法。来自同一父级的其他类在编译时已知大小,因此没有问题。
我想避免在使用展示位置新时需要考虑的一些特殊注意事项,并且我希望能够以正常方式删除对象。
我想避免在我的对象体内携带指针,部分是为了避免与复制对象相关的所有权问题,部分是因为我想尽可能多地重用现有的C代码。如果所有权是唯一的问题,我可能只是使用共享指针而不用担心。
以下是创建对象的C代码的精简版:
typedef struct
{
int controls;
int coords;
} myobject;
myobject* create_obj(int controls, int coords)
{
size_t size = sizeof(myobject) + (controls + coords*2) * sizeof(double);
char* mem = malloc(size);
myobject* p = (myobject *) mem;
p->controls = controls;
p->coords = coords;
return p;
}
对象内的数组维持对象生命周期的固定大小。在上面的代码中,遵循myobject
结构的内存将用于保存数组元素。
我觉得我可能会遗漏一些明显的东西。有什么方法我不知道在C ++中编写一个(相当)正常的构造函数,但是能够告诉它在运行时对象需要多少内存,而不需要求助于“放置新的”场景?
答案 0 :(得分:2)
实用方法如何:保持结构不变(如果与C的兼容性很重要)并将其包装到c ++类中?
typedef struct
{
int controls;
int coords;
} myobject;
myobject* create_obj(int controls, int coords);
void dispose_obj(myobject* obj);
class MyObject
{
public:
MyObject(int controls, int coords) {_data = create_obj(controls, coords);}
~MyObject() {dispose_obj(_data);}
const myobject* data() const
{
return _data;
}
myobject* data()
{
return _data;
}
int controls() const {return _data->controls;}
int coords() const {return _data->coords;}
double* array() { return (double*)(_data+1); }
private:
myobject* _data;
}
答案 1 :(得分:1)
为了维护原始代码的语义,其中struct和array位于一个独特的内存块中,您只需将malloc(size)
替换为new char[size]
代替:
myobject* create_obj(int controls, int coords)
{
size_t size = sizeof(myobject) + (controls + coords*2) * sizeof(double);
char* mem = new char[size];
myobject* p = new(mem) myobject;
p->controls = controls;
p->coords = coords;
return p;
}
在使用delete[]
释放内存时,您必须使用类型转换,但是:
myobject *p = create_obj(...);
...
p->~myobject();
delete[] (char*) p;
在这种情况下,我建议将该逻辑包装在另一个函数中:
void free_obj(myobject *p)
{
p->~myobject();
delete[] (char*) p;
}
myobject *p = create_obj(...);
...
free_obj(p);
话虽如此,如果你被允许,最好重新编写代码来代替C ++语义,例如:
struct myobject
{
int controls;
int coords;
std::vector<double> values;
myobject(int acontrols, int acoords) :
controls(acontrols),
coords(acoords),
values(acontrols + acoords*2)
{
}
};
然后你可以这样做:
std::unique_ptr<myobject> p = std::make_unique<myobject>(...); // C++14
...
std::unique_ptr<myobject> p(new myobject(...)); // C++11
...
std::auto_ptr<myobject> p(new myobject(...)); // pre C++11
...
答案 2 :(得分:1)
虽然我理解限制对现有C代码进行更改的愿望,但最好现在正确地执行它,而不是在将来与bug作斗争。我建议你对代码进行以下结构和更改来处理它(我怀疑它主要是提取计算偏移量的代码)。
struct spots
{
double x;
double y;
};
struct myobject
{
std::vector<double> m_controls;
std::vector<spots> m_coordinates;
myobject( int controls, int coordinates ) :
m_controls( controls ),
m_coordinates( coordinates )
{ }
};
答案 3 :(得分:-1)
当评论最终对实际要求有所了解时,解决方案将如下:
以下是:
class myobject {
myobject(int controls, int coords) : controls(controls), coords(coords) {}
~myobject() {};
public:
const int controls;
const int coords;
static myobject* create(int controls, int coords) {
std::unique_ptr<char> buffer = new char[sizeof(myobject) + (controls + coords*2) * sizeof(double)];
myobject obj* = new (buffer.get()) myobject(controls, coords);
buffer.release();
return obj;
}
void dispose() {
~myobject();
char* p = (char*)this;
delete[] p;
}
};
myobject *p = myobject::create(...);
...
p->dispose();
(或适当包装在智能指针的删除器中)
答案 4 :(得分:-1)
新答案(由OP发表评论):
分配正确大小的std::vector<byte>
。分配给向量的数组将是连续的内存。可以计算此向量大小,向量将正确管理您的内存。您仍然需要非常小心如何管理对该字节数组的访问,但至少可以使用迭代器等(如果需要)。
顺便说一下,这是一个小模板的东西,我用它来移动字节blob更加优雅(注意这有别名问题,正如谢尔盖在下面的评论中所指出的那样,我&#39 ;我把它留在这里,因为它似乎是一个不做的好例子...... :-)):
template<typename T>
T readFromBuf(byte*& ptr) {
T * const p = reinterpret_cast<T*>(ptr);
ptr += sizeof(T);
return *p;
}
旧答案:
正如评论所示,您可以轻松使用std::vector
来做您想做的事情。我还想提出另一个建议。
size_t size = sizeof(myobject) + (controls + coords*2) * sizeof(double);
上面一行代码告诉我你有一些隐藏的结构&#34;在你的代码中。您的myobject
结构有两个int
值,您可以从中计算实际需要的大小。你真正需要的是:
struct ControlCoord {
double control;
std::pair<double, double> coordinate;
};
std::vector<ControlCoord>> controlCoords;