我有一个简单的程序,它生成两个点(由整数向量组成)并找到两个不同点的两个向量的并集。但是有一些奇怪的编译错误,我无法弄清楚。
#include <iostream> // std::cout
#include <algorithm> // std::set_union, std::sort
#include <vector> // std::vector
#include <stdio.h>
#include <stdint.h>
#include <cstdint>
using namespace std;
struct Point {
std::vector<uint32_t> vec;
};
vector<uint32_t> inter_section( const Point& p1, const Point& p2 )
{
vector<uint32_t> v3;
sort(p1.vec.begin(), p1.vec.end());
sort(p2.vec.begin(), p2.vec.end());
set_intersection(p1.vec.begin(),p1.vec.end(),p2.vec.begin(),p2.vec.end(),back_inserter(v3));
return v3;
}
int main () {
Point p1, p2;
vector<uint32_t> res = inter_section(p1, p2);
return 0;
}
编译错误是
In file included from /usr/include/c++/4.8.2/algorithm:62:0,
from testUnion.cpp:3:
/usr/include/c++/4.8.2/bits/stl_algo.h: In instantiation of ‘void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<const unsigned int*, std::vector<unsigned int> >]’:
/usr/include/c++/4.8.2/bits/stl_algo.h:2211:62: required from ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<const unsigned int*, std::vector<unsigned int> >]’
/usr/include/c++/4.8.2/bits/stl_algo.h:5462:47: required from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<const unsigned int*, std::vector<unsigned int> >]’
testUnion.cpp:18:38: required from here
/usr/include/c++/4.8.2/bits/stl_algo.h:2142:17: error: assignment of read-only location ‘__first.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator*<const unsigned int*, std::vector<unsigned int> >()’
*__first = _GLIBCXX_MOVE(__val);
答案 0 :(得分:3)
在概念之前的C ++中,模板方法的编译错误很难跟上它们的起源。这在未来的C ++中应该有所改进,但是现在,我们需要具备解释它们的技能。
第一个开始的地方是 required from here
,它确定哪个源代码行是问题(这里是对std::sort
的调用),以及以下行,显示违反程序语义的最终操作: assignment of read-only location
。
为什么它是只读位置?好吧,回顾一下扩展,我们有一个__gnu_cxx::__normal_iterator<const unsigned int*, std::vector<unsigned int> >
。这是std::vector<uint32_t>::const_iterator
的内部表示;需要注意的重要事项是const unsigned int*
,而不仅仅是unsigned int*
,就像在相应的可变迭代器中一样。
为什么我们得到const_iterator
?向量的begin()
方法已重载;如果向量是const,我们得到一个const_iterator
。 end()
方法也是如此。
为什么向量是常数?它来自(引用a)const Point
对象。
该函数将p1
和p2
作为对const Point
个对象的引用。
在const Point
内,vec
成员为const std::vector<uint32_t>
。
begin()
的{{1}}和end()
方法均返回const std::vector<uint32_t>
。
您无法通过std::vector<uint32_t>::const_iterator
进行书写。
如果您愿意修改const_iterator
和p1
引用的对象,可以将它们作为对可修改p2
的引用传递:
Point
否则,您需要处理该向量的副本。您可以按值传递std::vector<uint32_t> inter_section(Point& p1, Point& p2)
{
std::sort(p1.vec.begin(), p1.vec.end());
std::sort(p2.vec.begin(), p2.vec.end());
std::vector<uint32_t> v3;
std::set_intersection(p1.vec.begin(), p1.vec.end(),
p2.vec.begin(), p2.vec.end(),
std::back_inserter(v3));
return v3;
}
和p1
,但一般情况下,您只需将您需要的内容(在本例中为p2
成员)复制到您的函数中的相应本地中:
vec
这是程序的固定版本,减去未使用的标头和(脆弱)std::vector<uint32_t> inter_section(const Point& p1, const Point& p2)
{
auto v1 = p1.vec;
auto v2 = p2.vec;
std::sort(v1.begin(), v1.end());
std::sort(v2.begin(), v2.end());
std::vector<uint32_t> v3;
std::set_intersection(v1.begin(), v1.end(),
v2.begin(), v2.end(),
std::back_inserter(v3));
return v3;
}
:
using namespace std;