我有一个简单的程序,该程序生成两个点(由整数的向量组成(,并找到两个不同点的向量的联合。但是我无法弄清楚一些奇怪的编译错误。
#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);
分析
在概念之前,在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()
和 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;
:
#include <algorithm>
#include <cstdint>
#include <vector>
struct Point {
std::vector<uint32_t> 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;
}
int main () {
Point p1, p2;
std::vector<uint32_t> res = inter_section(p1, p2);
}