无法迭代其元素包含uniq_ptr的map

Mic*_*vko 0 c++ unique-ptr c++11

以下代码无法编译:

#include <iostream>
#include <memory>
#include <map>

struct HaveUniq {
    std::unique_ptr<int> uniq;
};

void print_hus(const std::map<int, HaveUniq>& hus) {
    for (const std::pair<int, HaveUniq>& p: hus)
        std::cout << *p.second.uniq << std::endl;
}

int main() {
    std::map<int, HaveUniq> hus;
    for (int i = 0; i < 10; ++i)
        hus[i].uniq = std::unique_ptr<int>(new int(i));
    print_hus(hus);
}
Run Code Online (Sandbox Code Playgroud)

出现以下错误:

uniq_wtf.cpp: In function ‘void print_hus(const std::map<int, HaveUniq>&)’:
uniq_wtf.cpp:10:42: error: invalid initialization of reference of type 
‘const std::pair<int, HaveUniq>&’ from expression of type
‘const std::pair<const int, HaveUniq>’
for (const std::pair<int, HaveUniq>& p: hus)
Run Code Online (Sandbox Code Playgroud)

因此,它尝试迭代值而不是常量引用,并且它不能将这些值强制转换为引用.

很明显,具有unique_ptr作为其字段之一的对象不能具有默认复制构造函数.但是,如果我理解正确,迭代地图不涉及复制,所以它应该不是问题.或者地图迭代器实际上是否复制了值?为什么在引用值时会出现问题呢?

顺便说一下,如果用简单整数替换unique_ptr,并且用std :: array替换map,则代码可以工作.

For*_*veR 7

编译器错误非常清楚.std::map::value_type实际上std::pair<const Key, Value>,这只是让你的代码工作:

for (const std::pair<const int, HaveUniq>& p: hus)
Run Code Online (Sandbox Code Playgroud)

要不就

for (const auto& p : hus)
Run Code Online (Sandbox Code Playgroud)

实例


min*_*iot 6

ForEveR的答案显示了如何解决您的问题,但它并没有完全解释为什么您首先遇到这个问题.事情是,它只发生在unique_ptr.那么让我们再看一下吧.我写了这个测试程序:

#include <map>
#include <string>
#include <memory>

struct Foo { std::string bar; };
struct Bar { std::unique_ptr<int> bar; };

int main()
{
  std::map<int, Foo> mfoo;
  mfoo[23] = Foo { "foo" };
  for (const auto& foo : mfoo) { }
  for (const std::pair<const int, Foo>& foo : mfoo) { }
  for (const std::pair<int, Foo>& foo : mfoo) { }

  std::map<int, Bar> mbar;
  mbar[23].bar = std::unique_ptr<int>(new int(42));
  for (const auto& bar : mbar) { }
  for (const std::pair<const int, Bar>& bar : mbar) { }
  for (const std::pair<int, Bar>& bar : mbar) { }       // <-- FAILS

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

一切正常,但在您的示例中,只有标记的行失败.在我的例子中,编译器错误有点帮助:

$ g++ -std=c++11 -o test test.cpp
test.cpp: In function ‘int main()’:
test.cpp:20:41: error: invalid user-defined conversion from ‘std::pair<const int, Bar>’ to ‘const std::pair<int, Bar>&’ [-fpermissive]
   for (const std::pair<int, Bar>& bar : mbar) { }
                                         ^
In file included from /usr/include/c++/4.8/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/4.8/bits/stl_tree.h:61,
                 from /usr/include/c++/4.8/map:60,
                 from test.cpp:1:
/usr/include/c++/4.8/bits/stl_pair.h:150:12: note: candidate is: constexpr std::pair<_T1, _T2>::pair(std::pair<_U1, _U2>&&) [with _U1 = const int; _U2 = Bar; <template-parameter-2-3> = void; _T1 = int; _T2 = Bar] <near match>
  constexpr pair(pair<_U1, _U2>&& __p)
            ^
/usr/include/c++/4.8/bits/stl_pair.h:150:12: note:   no known conversion for argument 1 from ‘std::pair<const int, Bar>’ to ‘std::pair<const int, Bar>&&’
test.cpp:20:41: error: cannot bind ‘std::pair<const int, Bar>’ lvalue to ‘std::pair<const int, Bar>&&’
   for (const std::pair<int, Bar>& bar : mbar) { }
                                         ^
In file included from /usr/include/c++/4.8/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/4.8/bits/stl_tree.h:61,
                 from /usr/include/c++/4.8/map:60,
                 from test.cpp:1:
/usr/include/c++/4.8/bits/stl_pair.h:150:12: error:   initializing argument 1 of ‘constexpr std::pair<_T1, _T2>::pair(std::pair<_U1, _U2>&&) [with _U1 = const int; _U2 = Bar; <template-parameter-2-3> = void; _T1 = int; _T2 = Bar]’
  constexpr pair(pair<_U1, _U2>&& __p)
Run Code Online (Sandbox Code Playgroud)

我们可以从中收集:由于请求的类型与具有a的实际返回类型std::pair<int, Bar>完全匹配,因此需要创建副本.并且它无法做到这一点.constintunique_ptr

这就是为什么我们得到关于编译器无法绑定pair到的抱怨lvalue.