无法迭代其元素包含 uniq_ptr 的地图
Cannot iterate over map whose elements hold a uniq_ptr
以下代码无法编译:
#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);
}
出现以下错误:
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)
因此,它尝试迭代值而不是常量引用,并且它不能将这些值强制转换为引用。
很明显,具有 unique_ptr 作为其字段之一的对象不能具有默认的复制构造函数。但如果我理解正确的话,遍历地图不涉及复制,所以这应该不是问题。
还是地图迭代器实际上复制了值?
为什么它会在将值强制转换为引用时出现问题?
顺便说一下,如果将 unique_ptr 替换为简单整数,并且如果将地图替换为 std::array,则代码有效。
编译错误很明显。 std::map::value_type
实际上是 std::pair<const Key, Value>
,所以只有这样才能使您的代码正常工作:
for (const std::pair<const int, HaveUniq>& p: hus)
或者只是
for (const auto& p : hus)
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;
}
一切正常,但如您的示例所示,只有标记的行失败。就我而言,编译器错误虽然更有帮助:
$ 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)
我们可以从中收集到什么:因为请求的类型 std::pair<int, Bar>
不 完全 匹配具有 [=14 的实际返回类型=]int
,需要创建一个副本。它不能用 unique_ptr
.
做到这一点
这就是为什么我们抱怨编译器无法将 pair
绑定到 lvalue
。
以下代码无法编译:
#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);
}
出现以下错误:
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)
因此,它尝试迭代值而不是常量引用,并且它不能将这些值强制转换为引用。
很明显,具有 unique_ptr 作为其字段之一的对象不能具有默认的复制构造函数。但如果我理解正确的话,遍历地图不涉及复制,所以这应该不是问题。 还是地图迭代器实际上复制了值? 为什么它会在将值强制转换为引用时出现问题?
顺便说一下,如果将 unique_ptr 替换为简单整数,并且如果将地图替换为 std::array,则代码有效。
编译错误很明显。 std::map::value_type
实际上是 std::pair<const Key, Value>
,所以只有这样才能使您的代码正常工作:
for (const std::pair<const int, HaveUniq>& p: hus)
或者只是
for (const auto& p : hus)
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;
}
一切正常,但如您的示例所示,只有标记的行失败。就我而言,编译器错误虽然更有帮助:
$ 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)
我们可以从中收集到什么:因为请求的类型 std::pair<int, Bar>
不 完全 匹配具有 [=14 的实际返回类型=]int
,需要创建一个副本。它不能用 unique_ptr
.
这就是为什么我们抱怨编译器无法将 pair
绑定到 lvalue
。