我是否需要在 C++/CLI 中删除非托管对象
Do I need to delete unmanaged objects in C++/CLI
我有一个调用 C 结构和方法的 C++/CLI 方法:
在 C 头文件中:
typedef struct {
int left;
int top;
int right;
int bottom;
} frame_t;
typedef struct {
int width;
int height;
int group;
int nb_hints;
frame_t *hints;
frame_t view;
frame_t dest;
int page;
} image_t;
int resize_to_fill(image_t *image, int width, int height);
C++/CLI 包装器:
public ref class Frame {
public:
int Left;
int Top;
int Right;
int Bottom;
property int Width {
int get() {
return (Right - Left);
}
}
property int Height {
int get() {
return (Bottom - Top);
}
}
Frame() {
Top = 0;
Left = 0;
Bottom = 0;
Right = 0;
}
internal:
frame_t ToNative() {
frame_t f;
f.left = Left;
f.top = Top;
f.right = Right;
f.bottom = Bottom;
return f;
}
Frame(const frame_t &f) {
Left = f.left;
Top = f.top;
Right = f.right;
Bottom = f.bottom;
}
};
public ref class Image {
private:
void init(int nb_hints) {
this->view = gcnew Frame();
this->dest = gcnew Frame();
this->page = 0;
this->Hints = gcnew array<Frame^>(nb_hints);
}
public:
int Width;
int Height;
array<Frame^>^ Hints;
property int Group {
int get() {
return group;
}
}
property int Page {
int get() {
return this->page;
}
}
property Frame^ View {
Frame^ get() {
return this->view;
}
}
property Frame^ Dest {
Frame^ get() {
return this->dest;
}
}
Image(int nb_hints) {
this->init(nb_hints);
}
Image() {
this->init(0);
}
internal:
Frame^ view;
Frame^ dest;
int page;
int group;
Image(image_t native) {
this->Width = native.width;
this->Height = native.height;
this->Hints = gcnew array<Frame^>(native.nb_hints);
for (int i = 0; i < native.nb_hints; i++)
{
this->Hints[i] = gcnew Frame(native.hints[i]);
}
this->group = native.group;
this->page = native.page;
this->dest = gcnew Frame(native.dest);
this->view = gcnew Frame(native.view);
}
image_t ToNative() {
image_t i;
i.width = this->Width;
i.height = this->Height;
i.group = this->Group;
// hints
i.nb_hints = this->Hints->Length;
i.hints = new frame_t[this->Hints->Length];
for (int nb = 0; nb < this->Hints->Length; nb++)
{
i.hints[nb] = this->Hints[nb]->ToNative();
}
// output values
i.page = this->Page;
i.view = this->View->ToNative();
i.dest = this->Dest->ToNative();
return i;
}
};
// later, in another class
static int ResizeToFill(Image^ %image, int width, int height) {
image_t native = image->ToNative();
int result = resize_to_fill(&native, width, height);
image = gcnew Image(native);
// do I need to do this ?
delete *native;
return result;
}
我需要删除原生结构实例吗?
我已经搜索过这个答案,但它更多地涉及处理托管资源而不是非托管资源,这对大多数人来说似乎是显而易见的。我是 C/C++ 的新手,所以我没有所有的内存管理反应。
您只需要为动态创建的对象释放内存,当变量超出范围时,静态对象将被析构函数销毁。
image = gcnew Image(native);
这完全取决于这条语句的作用。您使用的库不是普通库,并且图像包装器 class 不是 System::Drawing::Image,因此仅从您的代码片段无法判断。
这个库的程序员可以通过两种方式实现它。如果他的做法很聪明,那么他就把它当作你的问题并创建了一个 浅拷贝。换句话说,一个新的 Image 实例与 native 共享相同的底层像素缓冲区。或者他可以创建一个 深拷贝 并为 Image 对象创建一个新的像素缓冲区。在这种情况下,您可以安全地销毁 image_t 对象。
.NET 中也存在这种差异,Bitmap::Clone() 进行浅拷贝,Bitmap(Image^) 构造函数进行深拷贝。两者差别很大,浅拷贝最多需要几把纳秒。如果图像很大,深度复制需要的时间会长得多,可能是 毫秒。
如果处理浅拷贝非常痛苦,您可能无法更改图像的终结器 class。您必须保留 image_t* 并获得一个良好的信号,表明 Image 对象不再使用,以便您可以安全地删除它。您将不得不显着重构您的代码。如果你猜错了,那么你就会遇到一个非常讨厌的问题,它不能保证让你的代码崩溃。您有一个不太可能导致访问冲突的悬空指针。测试时似乎工作正常,损坏显示的图像或在您不查看时无法诊断地使程序崩溃。
查看库的源代码或文档以了解它的作用非常重要。
我有一个调用 C 结构和方法的 C++/CLI 方法:
在 C 头文件中:
typedef struct {
int left;
int top;
int right;
int bottom;
} frame_t;
typedef struct {
int width;
int height;
int group;
int nb_hints;
frame_t *hints;
frame_t view;
frame_t dest;
int page;
} image_t;
int resize_to_fill(image_t *image, int width, int height);
C++/CLI 包装器:
public ref class Frame {
public:
int Left;
int Top;
int Right;
int Bottom;
property int Width {
int get() {
return (Right - Left);
}
}
property int Height {
int get() {
return (Bottom - Top);
}
}
Frame() {
Top = 0;
Left = 0;
Bottom = 0;
Right = 0;
}
internal:
frame_t ToNative() {
frame_t f;
f.left = Left;
f.top = Top;
f.right = Right;
f.bottom = Bottom;
return f;
}
Frame(const frame_t &f) {
Left = f.left;
Top = f.top;
Right = f.right;
Bottom = f.bottom;
}
};
public ref class Image {
private:
void init(int nb_hints) {
this->view = gcnew Frame();
this->dest = gcnew Frame();
this->page = 0;
this->Hints = gcnew array<Frame^>(nb_hints);
}
public:
int Width;
int Height;
array<Frame^>^ Hints;
property int Group {
int get() {
return group;
}
}
property int Page {
int get() {
return this->page;
}
}
property Frame^ View {
Frame^ get() {
return this->view;
}
}
property Frame^ Dest {
Frame^ get() {
return this->dest;
}
}
Image(int nb_hints) {
this->init(nb_hints);
}
Image() {
this->init(0);
}
internal:
Frame^ view;
Frame^ dest;
int page;
int group;
Image(image_t native) {
this->Width = native.width;
this->Height = native.height;
this->Hints = gcnew array<Frame^>(native.nb_hints);
for (int i = 0; i < native.nb_hints; i++)
{
this->Hints[i] = gcnew Frame(native.hints[i]);
}
this->group = native.group;
this->page = native.page;
this->dest = gcnew Frame(native.dest);
this->view = gcnew Frame(native.view);
}
image_t ToNative() {
image_t i;
i.width = this->Width;
i.height = this->Height;
i.group = this->Group;
// hints
i.nb_hints = this->Hints->Length;
i.hints = new frame_t[this->Hints->Length];
for (int nb = 0; nb < this->Hints->Length; nb++)
{
i.hints[nb] = this->Hints[nb]->ToNative();
}
// output values
i.page = this->Page;
i.view = this->View->ToNative();
i.dest = this->Dest->ToNative();
return i;
}
};
// later, in another class
static int ResizeToFill(Image^ %image, int width, int height) {
image_t native = image->ToNative();
int result = resize_to_fill(&native, width, height);
image = gcnew Image(native);
// do I need to do this ?
delete *native;
return result;
}
我需要删除原生结构实例吗?
我已经搜索过这个答案,但它更多地涉及处理托管资源而不是非托管资源,这对大多数人来说似乎是显而易见的。我是 C/C++ 的新手,所以我没有所有的内存管理反应。
您只需要为动态创建的对象释放内存,当变量超出范围时,静态对象将被析构函数销毁。
image = gcnew Image(native);
这完全取决于这条语句的作用。您使用的库不是普通库,并且图像包装器 class 不是 System::Drawing::Image,因此仅从您的代码片段无法判断。
这个库的程序员可以通过两种方式实现它。如果他的做法很聪明,那么他就把它当作你的问题并创建了一个 浅拷贝。换句话说,一个新的 Image 实例与 native 共享相同的底层像素缓冲区。或者他可以创建一个 深拷贝 并为 Image 对象创建一个新的像素缓冲区。在这种情况下,您可以安全地销毁 image_t 对象。
.NET 中也存在这种差异,Bitmap::Clone() 进行浅拷贝,Bitmap(Image^) 构造函数进行深拷贝。两者差别很大,浅拷贝最多需要几把纳秒。如果图像很大,深度复制需要的时间会长得多,可能是 毫秒。
如果处理浅拷贝非常痛苦,您可能无法更改图像的终结器 class。您必须保留 image_t* 并获得一个良好的信号,表明 Image 对象不再使用,以便您可以安全地删除它。您将不得不显着重构您的代码。如果你猜错了,那么你就会遇到一个非常讨厌的问题,它不能保证让你的代码崩溃。您有一个不太可能导致访问冲突的悬空指针。测试时似乎工作正常,损坏显示的图像或在您不查看时无法诊断地使程序崩溃。
查看库的源代码或文档以了解它的作用非常重要。