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

发布于 2024-07-27 04:10:34 字数 2508 浏览 2 评论 0原文

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

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

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

但是,在使用 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)

Update: Edited code example to use AutoA for the workaround (which was the original intention). Realized this after seeing rlbond's answer.

I am trying to incorporate the usage of auto_ptr in my code based on recommendations from this thread:

Express the usage of C++ arguments through method interfaces

However, I am receiving some unexpected compile errors when compiling with Visual Studio 6.0. It has a problem when dealing with assignments/copies of a std::auto_ptr of a derived type to a std::auto_ptr of the base type. Is this an issue specific to my compiler?

I know there's a strong recommendation to use Boost, but on my project it is not an option. If I still want to use auto_ptr, am I forced to use the workaround of calling std::auto_ptr::release()? From what I have encountered so far, this issue results in a compiler error, so it's easy enough to catch. However, could adopting the convention of calling release to assign to a 'auto_ptr' of base type throughout expose me to any maintenance issues? Especially if built with a different compiler (assuming other compilers don't have this issue).

If the release() workaround is not good due to my circumstances, should I fall back on using a different convention for describing transfer of ownership?

The following is an example illustrating the problem.

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

Compile Error:

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

薔薇婲 2024-08-03 04:10:34

第一个很简单:

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 by value,因此由编译器隐式创建的临时 std::auto_ptr 需要复制构造sink 的参数中。 现在,像这样的临时变量是右值。 右值不绑定到非常量引用,但 std::auto_ptr 的“复制构造函数”通过非常量引用获取其参数。

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

第二个的解决方法:

AutoA tmp( b_raw_to_b_auto/*.release() for VC6*/ );
sink( tmp );

The first one is easy:

AutoA b_auto_to_a_auto(b_auto);  //fails to compile

This fails on VC6 since it requires member function templates, something VC6's standard library doesn't support. It compiles on standard-compliant compilers, though.

Workaround:

AutoA b_auto_to_a_auto( b_auto.release() );

The second one is much more subtle :)

sink(b_raw_to_b_auto);  //fails to compile

This one shouldn't compile on a standards-compliant compiler, because there's an implicit conversion going on. The compiler turns the above into

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

however, sink takes std::auto_ptr<A> by value, so the temporary std::auto_ptr<A> created implicitly by the compiler needs to be copy-constructed into the argument to sink. Now, temporaries like that are rvalues. Rvalues don't bind to non-const references, but std::auto_ptr's "copy constructor" takes it's argument by non-const reference.

There you go - compile error. AFAICS this is standards-conforming behaviour. C++-0x "move semantics" will fix that by adding a "copy constructor" that takes an rvalue reference, though I'm not sure how much love std::auto_ptr will still receive in the future, what with std::shared_ptr and all.

Workaround for the second one:

AutoA tmp( b_raw_to_b_auto/*.release() for VC6*/ );
sink( tmp );
青春有你 2024-08-03 04:10:34
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 吗?

AutoA b_auto_to_a_auto(b_auto);  //fails to compile

sink(b_raw_to_b_auto);  //fails to compile

Pavel Minaev points out something I actually didn't know:

The first call should compile, because there is an implicit conversion from a B* to an A*.
However, the second will not compile. The following will:

sink(static_cast<AutoA>(b_raw_to_b_auto));

VC6 is notorious for not being very good with templates.

I highly suggest you upgrade your code base to one that actually works and begin using RAII techniques, especially boost::shared_ptr. I know you say you can't, and I know it's difficult, but you will have virtually no memory leaks and many, many fewer bugs.

Then again, maybe even without full functionality you can use auto_ptr?

风和你 2024-08-03 04:10:34

这里有两个问题。 首先,

AutoA b_auto_to_a_auto(b_auto);  

完全符合标准并且应该可以编译。 让我解释一下原因。 ISO C++ 标准为 auto_ptr(以及其他)指定 (20.4.5.1[lib.auto.ptr.cons]/4-6) 以下构造函数;

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

请注意,此处的 YX 是不同的类型。 该标准还指出:

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

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

sink(b_raw_to_b_auto);  //fails to compile

这个问题实际上由 mmutz 完美地解释了,所以我不会在这里详细介绍 - 请参阅他的答案。 总而言之:是的,这一行不应该编译,并且不会在兼容的编译器(或 VC6,正如您所发现的)中。

There are two issues here. First of all, this:

AutoA b_auto_to_a_auto(b_auto);  

It is perfectly standard compliant and should compile. Let me explain why. ISO C++ standard specifies (20.4.5.1[lib.auto.ptr.cons]/4-6) the following constructor for auto_ptr<X> (among others);

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

Note that Y is a different type from X here. And the Standard furthermore says:

Requires: Y* can be implicitly converted to X*.

The only thing to pay attention to here is that constructor argument is a reference-to-non-const. For your case, this isn't a problem (since you're passing a non-const variable there), but it becomes important for the next part. To conclude here: what you're seeing is non-standard behavior in VC6. It should compile on a compliant compiler (and will compile on VC7 and above). Now on to the second thing:

sink(b_raw_to_b_auto);  //fails to compile

This one is actually perfectly explained by mmutz, so I won't go into details here - see his answer. To conclude on that: yes, this line shouldn't compile, and won't in a compliant compiler (or VC6, as you've found out).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文