std :: auto_ptr Visual Studio 6.0中的编译问题

时间:2009-07-17 00:25:28

标签: c++ visual-studio-6

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

我正在尝试根据此主题的建议在我的代码中加入auto_ptr的用法:

Express the usage of C++ arguments through method interfaces

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

我知道强烈建议使用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)

3 个答案:

答案 0 :(得分: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通过 获取std::auto_ptr<A> ,因此编译器隐式创建的临时std::auto_ptr<A>需要< em> copy-construct sink的参数中。现在,像这样的临时工具是 rvalues 。 Rvalues不绑定到非const引用,但std::auto_ptr的“复制构造函数”通过非const 引用获取它的参数。

你去 - 编译错误。 AFAICS这是符合标准的行为。 C ++ - 0x“移动语义”将通过添加一个带有右值引用的“复制构造函数”来修复它,虽然我不确定将来还会收到多少爱std::auto_ptr,{{1}和所有。

第二个解决方法:

std::shared_ptr

答案 1 :(得分: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

答案 2 :(得分: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();

请注意,YX的版本不同。标准还说:

  

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

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

sink(b_raw_to_b_auto);  //fails to compile

这个实际上是由mmutz完美解释的,所以我不会在这里详细说明 - 请参阅他的回答。总结一下:是的,这一行不应该编译,也不会在兼容的编译器(或VC6,你已经发现)中。