更新:编辑代码示例以使用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)
答案 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();
请注意,Y
与X
的版本不同。标准还说:
要求:Y *可以隐式转换为X *。
这里唯一要注意的是构造函数参数是对非const的引用。对于你的情况,这不是一个问题(因为你在那里传递一个非const变量),但它对下一部分变得很重要。总结一下:您所看到的是VC6中的非标准行为。它应在兼容的编译器上编译(并将在VC7及更高版本上编译)。现在进行第二件事:
sink(b_raw_to_b_auto); //fails to compile
这个实际上是由mmutz完美解释的,所以我不会在这里详细说明 - 请参阅他的回答。总结一下:是的,这一行不应该编译,也不会在兼容的编译器(或VC6,你已经发现)中。