1

我正在尝试将 aboost::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 'Impl')。编译文件时,编译器在此函数的文件中check_shared.cpp停止:boost/checked_delete.hpptypedef

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
4

2 回答 2

1

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

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

(这是基于猜测您由于尝试破坏不完整的类型而导致编译错误。如果您遇到不同的错误,或意外的运行时行为,或者更改无法修复它,请更新问题以演示实际问题。)

于 2015-05-19T11:11:35.093 回答
1

这绝对是由于编译器错误。不幸的是,它仍然存在于 C++ Builder XE8 中。请参阅此处的相关问题,以及 Andy Prowl 的回答: C++ 编译器是否有效地隐式实例化模板类的所有成员函数?

此处向 Embarcadero 报告的问题: bcc32 编译器在使用带有 PIMPL 习惯用法的 std::auto_ptr 时导致未定义的行为,因为模板实例化规则不遵循 C++ 规范

如果您可以使用 Embarcadero 中一种较新的基于 clang 的编译器,那么您应该没问题。我的测试用例通过了 64 位 clang 编译器。

更新: 我们已经通过编写我们自己的智能指针类来解决这个问题,该类类似于unique_ptr它包含一个checked_delete未在类内内联实现的函数。相反,您必须在checked_delete还包含私有类实现的 ONE 翻译单元内显式实例化该函数。宏用于帮助解决这个问题。那是:

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;
}

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

于 2015-12-08T22:48:03.487 回答