奇怪的错误 - 为什么编译器试图调用复制构造函数?

发布于 2024-12-23 17:44:05 字数 1734 浏览 0 评论 0 原文

我收到一些非常奇怪的错误。由于某种我不明白的原因,编译器似乎想要调用复制构造函数。

(118) std::map<int, layer> xs;
(119) xs.begin()->first; // error?!

layer 是一种不可复制、可移动的类型。

class layer : public observable
{
    layer(const layer&);
    layer& operator=(const layer&);
public:
    layer(int index = -1);
    layer(layer&& other);
    layer& operator=(layer&& other);
   //...
};

由于某种原因,第 119 行导致编译器尝试调用 std::pair 的复制构造函数,为什么?

1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(131): error C2248: 'layer::layer' : cannot access private member declared in class 'layer'
1> ..\layer.h(55) : see declaration of 'layer::layer'
1> ..\layer.h(53) : see declaration of 'layer'
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(129) : while compiling class template member function 'std::_Pair_base<_Ty1,_Ty2>::_Pair_base(const std::_Pair_base<_Ty1,_Ty2> &)'
1> with
1> [
1>     _Ty1=const int,
1>     _Ty2=layer
1> ]
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(174) : see reference to class template instantiation 'std::_Pair_base<_Ty1,_Ty2>' being compiled
1> with
1> [
1>     _Ty1=const int,
1>     _Ty2=layer
1> ]
1> ..\stage.cpp(119) : see reference to class template instantiation 'std::pair<_Ty1,_Ty2>' being compiled
1> with
1> [
1>     _Ty1=const int,
1>     _Ty2=layer
1> ]

我也尝试过以下方法,但同样失败。

(118) std::map<int, layer> xs;
(119) auto& t1 = *xs.begin();
(120) auto& t2 = t1.first; // error?!

这是怎么回事?

I'm getting some very wierd errors. The compiler seems to want to call the copy constructor for some reason I don't understand.

(118) std::map<int, layer> xs;
(119) xs.begin()->first; // error?!

layer is a non-copyable, movable type.

class layer : public observable
{
    layer(const layer&);
    layer& operator=(const layer&);
public:
    layer(int index = -1);
    layer(layer&& other);
    layer& operator=(layer&& other);
   //...
};

For some reason the line 119 caused the compiler to try to invoke the copy constructor for std::pair, why?

1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(131): error C2248: 'layer::layer' : cannot access private member declared in class 'layer'
1> ..\layer.h(55) : see declaration of 'layer::layer'
1> ..\layer.h(53) : see declaration of 'layer'
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(129) : while compiling class template member function 'std::_Pair_base<_Ty1,_Ty2>::_Pair_base(const std::_Pair_base<_Ty1,_Ty2> &)'
1> with
1> [
1>     _Ty1=const int,
1>     _Ty2=layer
1> ]
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(174) : see reference to class template instantiation 'std::_Pair_base<_Ty1,_Ty2>' being compiled
1> with
1> [
1>     _Ty1=const int,
1>     _Ty2=layer
1> ]
1> ..\stage.cpp(119) : see reference to class template instantiation 'std::pair<_Ty1,_Ty2>' being compiled
1> with
1> [
1>     _Ty1=const int,
1>     _Ty2=layer
1> ]

I've also tried the following, where it fails similarly.

(118) std::map<int, layer> xs;
(119) auto& t1 = *xs.begin();
(120) auto& t2 = t1.first; // error?!

What is going on here?

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

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

发布评论

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

评论(3

少女七分熟 2024-12-30 17:44:05

这是模板错误的奇怪微妙之处之一。模板代码不是代码,它几乎更接近于生成代码的脚本语言。您甚至可能在函数中存在语法错误,但在您的代码(直接或间接)使用该函数之前,该函数不一定会生成编译器错误。

在这种情况下,xs.first()导致生成std::map::iterator,这也需要生成std::pair。 std::pair 的默认实现有一个复制构造函数,该构造函数无法编译。

您可以使用没有复制构造函数的 std::pair 模板专业化来解决此问题,但是您无法将任何内容插入到映射中。 xs[0] = myLayer 创建并插入 std::make_pair<0, myLayer>;到你的地图中,这显然需要复制构造一个图层。

典型的解决方案是将类型更改为 std::map; >。复制shared_ptr不会复制引用的对象。

This is one of the strange subtleties of template errors. Template code is not code, it's almost closer to a scripting language for generating code. You can even have a syntax error in a function that won't necessarily generate a compiler error until that function is used (directly or indirectly) by your code.

In this case xs.first() caused the generation of std::map<int, layer>::iterator, which also necessitates the generation of std::pair<int, layer>. The default implementation of std::pair has a copy constructor, which fails to compile.

You could get around this with a template specialization of std::pair which does not have the copy constructor, but then you can't insert anything into your map. xs[0] = myLayer creates and inserts std::make_pair<0, myLayer> into your map, which obviously requires the copy construction of a layer.

The typical solutions for this is to change your type to std::map<int, std::shared_ptr<layer> >. Copying a shared_ptr doesn't copy the referenced object.

提笔落墨 2024-12-30 17:44:05

这取决于您在何处初始化该成员及其第一个成员。
如果您将其初始化为静态成员或在堆栈上而不调用构造函数,它将尝试调用默认构造函数(不带参数),并且无法访问它,因为您已将其设为私有。

您必须为地图中的元素显式调用公共构造函数

It depends on where you initialize this member, and its first member.
If you initialize it as a static member or on the stack without calling the constructor it will try and call the default contructor (without parameters) and won't be able to access it since you have made it private.

You have to explicitly call the public constructor for elements in your map

原来是傀儡 2024-12-30 17:44:05

您的示例:

(118) std::map<int, layer> xs;
(119) xs.begin()->first; // error?!

根据 http://www.cplusplus.com/reference/stl/map/

xs.begin() Return iterator to beginning

...
它->第一; // 与 (*it).first (键值)相同,

因此

xs.begin()->first;

相当于

pair<int,layer> piltmp = (*xs.begin());
piltmp.first;

Et voila。地图中该对的副本已创建。其中涉及创建图层的副本。

(如果映射持有指向图层的指针或自动指针,而不是图层本身,这不会成为问题。)

现在,如果 map::iterator::operator-> 则不会发生这种情况。返回 value_type 引用,而不是 value_type。即,如果它返回左值而不是右值。似乎很奇怪,事实并非如此,但我还没有通过该标准。

您可以通过执行以下操作来绕过它

pair<int,layer>& piltmp = *xs.begin();
return piltmp.first;

(未经测试。)

Your example:

(118) std::map<int, layer> xs;
(119) xs.begin()->first; // error?!

Per http://www.cplusplus.com/reference/stl/map/

xs.begin() Return iterator to beginning

...
it->first; // same as (*it).first (the key value)

Therefore

xs.begin()->first;

is equivalent to

pair<int,layer> piltmp = (*xs.begin());
piltmp.first;

Et voila. A copy of the pair in the map has been created. Which involves creating a copy of the layer.

(This would not be a problem if the map held pointers or autopointers to layer, rather than a layer itself.)

Now, this would not be happening if map::iterator::operator-> returned a value_type reference, rather than a value_type. I.e. if it returned an lvalue rather than an rvalue. Seems strange that it does not, but I have not worked my way through the standard.

You might get around it by doing

pair<int,layer>& piltmp = *xs.begin();
return piltmp.first;

(Not tested.)

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