【问题标题】:How to delete objects of auto_ptr type in a C++ dll如何在 C++ dll 中删除 auto_ptr 类型的对象
【发布时间】:2013-05-23 17:17:15
【问题描述】:

在一个动态库中分配的内存然后在另一个库中删除通常会引发问题,如Memory allocation and deallocation across dll boundaries 所示。我的问题与 auto_ptr 类型的对象有关。由 dll 提供的这种类型的对象非常棘手,因为使用 dll 的程序会自动删除该对象。但是,经常会发生一些内存重新分配操作可能会发生在 dll 库中的 auto_ptr 类型对象上。因此编写一个销毁 auto_ptr 类型对象的函数是必要的。首先,我给出下面的例子,它说明了在 dll 库中销毁 auto_ptr 类型对象的重要性。

.dll库的头文件如下:

dll.h
class __declspec(dllexport) Image
{
public:
    Image()
    {
        mem = NULL;
    }
    ~Image()
    {
        std::cout<<"Image is being deleted!"<<std::endl;

        delete []mem;
        mem = NULL;

    }

    int *mem;

};

typedef std::auto_ptr<Image> ImagePtr;



class __declspec(dllexport) ImageReader
{
public:
    void memory_reset(Image &img)
    {
img.mem = new int [20*30];

    }
};

调用dll库的可执行程序如下:

#include "dll.h"
#include <iostream>
#include <vector>
#include <numeric>
#include <iostream>
#include <algorithm>
#include <functional>
#include <iterator>

int main()
{
    ImagePtr my_img(new Image());
    ImageReader bmp_reader;
    bmp_reader.memory_reset(*my_img);

    return 0;

}

如果调用的运行时库是静态链接的(Multi-threaded Debug (/MTd)),运行可执行程序时会报错:

为了解决这个问题,auto_ptr 对象必须被库删除。那么问题来了:删除这种类型的对象最好的方法是什么?我能想到的办法是提供一个可以删除auto_ptr对象的Global函数:

void Fun_destroy_memory(Image &img)
{
    img.~Image();
}

所以可执行程序会变成:

int main()
{
    ImagePtr my_img(new Image());
    ImageReader bmp_reader;
    bmp_reader.memory_reset(*my_img);
    Fun_destroy_memory(*my_img);

    return 0;

}   

我不知道这种情况是否有其他解决方案。另外,我想知道像我在Fun_destroy_memory 中那样直接调用类析构函数是否是一种好习惯。非常感谢!

【问题讨论】:

  • 直接调用析构函数是个坏主意。特别是对于 auto_ptr,因为我们知道 auto_ptr 会在某个时候尝试释放此内存。如果析构函数在它拥有的某个托管对象上调用删除操作,您将双重释放此内存。
  • 考虑改用std::unique_ptr&lt;,&gt;(仅限C++11),因为它允许您指定特定的删除函子类型并在您想要的任何位置执行删除。

标签: c++ visual-studio-2010


【解决方案1】:

auto_ptrs 负责管理它们所代表的对象。当 auto_ptr 超出范围时,他们管理的对象将被释放。您无法控制未使用“新”创建的任何变量的“生命周期”。因此,无法销毁此“auto_ptr”,它只会超出范围。如果您对此对象有范围问题,并且您肯定这就是问题所在(显然我不相信),您可以使用任意范围解析运算符概述代码部分,以管理某些变量的范围。我复制了你的代码来创建一个例子。

int main()
{
    //Do some work that doesn't need an ImagePtr
    ImageReader bmp_reader;
    { 
        ImagePtr my_img(new Image());
        bmp_reader.memory_reset(*my_img);
    } // the my_img pointer is no longer in scope and it's manage object will be freed          
    return 0;
}

请注意,我不一定建议这样做,坦率地说,我认为这看起来很糟糕,而且您的问题出在其他地方。但是,如果您绝对相信与 'bmp_reader' 相比管理 'my_img' 的生命周期会有所帮助,那么您就是这样做的。

为什么不直接修改memory_reset。如果一个对象/函数“控制”了一个对象,并使用它的托管内存做某事,那么它有责任确保在将这个指针的值分配给其他东西之前释放内存。我会推荐以下。

void memory_reset(Image &img)
{
    delete[] img.mem; //add this line
    img.mem = new int [20*30];
}

另外,请注意,在同一环境中将托管/垃圾收集/智能指针与新/删除内存管理类型的方案混合通常被认为是不良的编程习惯。

【讨论】:

    猜你喜欢
    • 2021-01-26
    • 2014-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多