2

更新:编辑代码示例以使用 AutoA 作为解决方法(这是最初的意图)。看到 rlbond 的答案后意识到这一点。

我正在尝试auto_ptr根据此线程的建议在我的代码中使用 :

通过方法接口表达 C++ 参数的用法

但是,在使用 Visual Studio 6.0 进行编译时,我收到了一些意外的编译错误。std::auto_ptr在处理派生类型的 astd::auto_ptr到基类型的 a 的分配/副本时,它会出现问题。这是我的编译器特有的问题吗?

我知道强烈建议使用 Boost,但在我的项目中它不是一个选项。如果我仍然想使用auto_ptr,我是否被迫使用调用的解决方法std::auto_ptr::release()?从我目前遇到的情况来看,这个问题会导致编译器错误,所以很容易捕捉到。但是,采用调用 release 的约定来分配给基本类型的“auto_ptr”是否会让我面临任何维护问题?特别是如果使用不同的编译器构建(假设其他编译器没有这个问题)。

如果release()由于我的情况,解决方法不好,我是否应该使用不同的约定来描述所有权转移?

以下是说明问题的示例。

#include "stdafx.h"
#include <memory>

struct A
{
    int x;
};

struct B : public A
{
    int y;
};

typedef std::auto_ptr<A> AutoA;
typedef std::auto_ptr<B> AutoB;

void sink(AutoA a)
{
    //Some Code....
}

int main(int argc, char* argv[])
{
    //Raws to auto ptr
    AutoA a_raw_to_a_auto(new A());
    AutoB b_raw_to_b_auto(new B());
    AutoA b_raw_to_a_auto(new B());

    //autos to same type autos
    AutoA a_auto_to_a_auto(a_raw_to_a_auto);
    AutoB b_auto_to_b_auto(b_raw_to_b_auto);

    //raw derive to auto base
    AutoB b_auto(new B());

    //auto derive to auto base
    AutoA b_auto_to_a_auto(b_auto);  //fails to compile

    //workaround to avoid compile error.
    AutoB b_workaround(new B());
    AutoA b_auto_to_a_auto_workaround(b_workaround.release());

    sink(a_raw_to_a_auto);
    sink(b_raw_to_b_auto);  //fails to compile

    return 0;
}

编译错误:

Compiling...
Sandbox.cpp
C:\Program Files\Microsoft Visual Studio\MyProjects\Sandbox\Sandbox.cpp(40) : error C2664: '__thiscall std::auto_ptr<struct A>::std::auto_ptr<struct A>(struct A *)' : cannot convert parameter 1 from 'class std::auto_ptr<struct B>' to 'struct A *'
        No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
C:\Program Files\Microsoft Visual Studio\MyProjects\Sandbox\Sandbox.cpp(47) : error C2664: 'sink' : cannot convert parameter 1 from 'class std::auto_ptr<struct B>' to 'class std::auto_ptr<struct A>'
        No constructor could take the source type, or constructor overload resolution was ambiguous
Error executing cl.exe.

Sandbox.exe - 2 error(s), 0 warning(s)
4

3 回答 3

5

第一个很简单:

AutoA b_auto_to_a_auto(b_auto);  //fails to compile

这在 VC6 上失败,因为它需要成员函数模板,VC6 的标准库不支持。不过,它可以在符合标准的编译器上编译。

解决方法:

AutoA b_auto_to_a_auto( b_auto.release() );

第二个更微妙:)

sink(b_raw_to_b_auto);  //fails to compile

这个不应该在符合标准的编译器上编译,因为正在进行隐式转换。编译器把上面的变成

sink( std::auto_ptr<A>( b_raw_to_b_auto ) );

但是,值取值sink,因此编译器隐式创建的临时变量需要复制构造到. 现在,像这样的临时对象是rvalues。右值不绑定到非常量引用,但' 的“复制构造函数”通过非常量引用获取它的参数。std::auto_ptr<A> std::auto_ptr<A>sinkstd::auto_ptr

你去 - 编译错误。AFAICS 这是符合标准的行为。C++-0x“移动语义”将通过添加一个接受右值引用的“复制构造函数”来解决这个问题,尽管我不确定std::auto_ptr未来还会收到多少爱,还有什么std::shared_ptr

第二个解决方法:

AutoA tmp( b_raw_to_b_auto/*.release() for VC6*/ );
sink( tmp );
于 2009-07-17T04:26:44.683 回答
4
AutoA b_auto_to_a_auto(b_auto);  //fails to compile

sink(b_raw_to_b_auto);  //fails to compile

Pavel Minaev 指出了一些我实际上不知道的事情:

第一次调用应该编译,因为从 B* 到 A* 的隐式转换。但是,第二个不会编译。以下将:

sink(static_cast<AutoA>(b_raw_to_b_auto));

VC6 因不擅长模板而臭名昭著。

我强烈建议您将您的代码库升级到一个真正有效的代码库并开始使用 RAII 技术,尤其是boost::shared_ptr. 我知道你说你不能,而且我知道这很困难,但是你几乎不会有内存泄漏和很多很多的错误。

再说一次,即使没有完整的功能,您也可以使用auto_ptr

于 2009-07-17T00:59:01.087 回答
2

这里有两个问题。首先,这个:

AutoA b_auto_to_a_auto(b_auto);  

完全符合标准,应该可以编译。让我解释一下为什么。ISO C++ 标准指定 (20.4.5.1[lib.auto.ptr.cons]/4-6) 的以下构造函数auto_ptr<X>(除其他外);

template<class Y> auto_ptr(auto_ptr<Y>&) throw();

请注意,这Y是与X此处不同的类型。该标准还说:

要求:Y* 可以隐式转换为 X*。

这里唯一要注意的是构造函数参数是对非常量的引用。对于您的情况,这不是问题(因为您在那里传递了一个非常量变量),但这对于下一部分变得很重要。在这里总结一下:您看到的是VC6 中的非标准行为。它应该在兼容的编译器上编译(并将在 VC7 及更高版本上编译)。现在说第二件事:

sink(b_raw_to_b_auto);  //fails to compile

mmutz实际上已经完美地解释了这一点,所以我不会在这里详细介绍 - 请参阅他的答案。总结一下:是的,这一行不应该编译,也不会在兼容的编译器(或 VC6,正如你所发现的那样)中编译。

于 2009-07-17T04:50:50.733 回答