为什么boost :: scoped_ptr会阻止BCL用于BCB6?

时间:2015-05-19 11:05:37

标签: c++ c++builder-6 boost-smart-ptr

我试图将boost::scoped_ptr与我的实现类一起使用,该实现类仅在包含类的cpp文件中可见。包含类有一个显式定义的析构函数(不是内联的),但我的编译器(Borland C ++ 5.6.4)无法编译。

如果我改为使用boost::shared_ptr,则相同的示例将按预期编译并运行。

我做错了什么?

编辑:很遗憾忘记在这里显示源代码,编译器错误和(预期)输出:

源代码

档案check_shared.cpp

// shortened.
#include "SmartPtrTest.h"
void check_shared()
{
    Containing t;
}

档案SmartPtrTest.h

#include <boost/noncopyable.hpp>
#include <boost/smart_ptr.hpp>

class Impl;
#define smart_ptr boost::scoped_ptr

class Containing: private boost::noncopyable
{
public:
    Containing();
    ~Containing();
private:
    smart_ptr<Impl> impl;
};

档案SmartPtrTest.cpp

#include "SmartPtrTest.h"
#include <iostream>

using namespace std;

class Impl {
public:
    Impl() {
        cout << "ctr Impl" << endl;
    }
    ~Impl() {
        cout << "dtr Impl" << endl;
    }
};

Containing::Containing(): impl(new Impl)
{
    cout << "ctr Containing" << endl;
}

Containing::~Containing()
{
    cout << "dtr Containing" << endl;
}

编译器错误

...类似于undefined structure 'Impl'(它的德语: Undefinierte Struktur&#39; Impl&#39; )。编译文件check_shared.cpp时,编译器在此函数的boost/checked_delete.hpp中的文件typedef中停止:

template<class T> inline void checked_delete(T * x)
{
    // intentionally complex - simplification causes regressions
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
    (void) sizeof(type_must_be_complete);
    delete x;
}

输出(预期)

我在使用boost::share_ptr时得到的输出结果显示ctr和dtr按预期调用。

ctr Impl
ctr Containing
dtr Containing
dtr Impl

2 个答案:

答案 0 :(得分:1)

只要“实现”类在智能指针可能被销毁的任何时刻完成,它就应该工作。这不仅发生在析构函数中,而且发生在构造函数中 - 如果它们因异常而退出,则必须销毁指针成员。

因此,请确保在实现类的定义之后,在源文件中定义了构造函数和析构函数。

(这是基于猜测你因为尝试销毁一个不完整的类型而得到编译错误。如果你得到不同的错误,或者意外的运行时行为,或者更改没有修复它,那么请更新问题以证明实际问题。)

答案 1 :(得分:1)

这绝对是由于编译器错误造成的。不幸的是它仍然存在于C ++ Builder XE8中。请在此处查看此相关问题,以及Andy Prowl的答案:Is it valid for a C++ compiler to implicitly instantiate ALL member functions of a template class?

问题报告给Embarcadero:bcc32 compiler causes undefined behavior when using std::auto_ptr with PIMPL idiom because template instantiation rules do not follow C++ spec

如果你可以使用Embarcadero的一个较新的基于clang的编译器,你应该没问题。我的测试用例传入了64位的clang编译器。

更新:我们通过编写与unique_ptr类似的智能指针类解决了这个问题,因为它包含一个未在线实现的checked_delete函数在课堂上。相反,您必须在一个包含私有类实现的一个翻译单元中显式实例化checked_delete函数。宏用于帮助解决这个问题。那就是:

template<class X> class unique_ptr_bcc32 {
    // Deletes the object using operator delete:
    private: static void checked_delete(X* p);
    // <snip>
}

稍后,在CPP文件中:

class PIMPL { /* snip implementation */ };

// You can simplify this by way of a macro:
template <> void unique_ptr_bcc32<PIMPL>::checked_delete(PIMPL* p) {
    typedef char type_must_be_complete[sizeof(PIMPL) ? 1 : -1];
    static_cast<void>(sizeof(type_must_be_complete));
    delete p;
}

当涉及模板实例化和删除时,编译器没有留下有趣的业务空间。