我需要一种迭代器,它允许我迭代容器中的所有元素组合(允许重复和{1,2}=={2,1}
)。我写了这个:
#include <iostream>
#include <map>
#include <vector>
template <typename T>
struct ChooseKfromN{
T mbegin;
T mend;
std::vector<T> combo;
ChooseKfromN(T first,T last,int k) : mbegin(first),mend(last),combo(k,first) {}
bool increment(){
for (auto it = combo.begin();it!=combo.end();it++){
if (++(*it) == mend){
if (it != combo.end()){
auto next = it;
next++;
auto nexit = (*next);
nexit++;
std::fill(combo.begin(),next,nexit);
}
} else { return true;}
}
std::cout << "THIS IS NEVER REACHED FOR A MAP !! \n" << std::endl;
return false;
}
typename std::vector<T>::const_iterator begin(){ return combo.begin();}
typename std::vector<T>::const_iterator end() { return combo.end();}
};
template <typename T>
ChooseKfromN<T> createChooseKfromN(T first,T last,int k) {
return ChooseKfromN<T>(first,last,k);
}
在std::map
...
int main(){
//std::vector<std::string> xx = {"A","B","C"};
std::map<int,int> xx;
xx[1] = 1;
xx[2] = 2;
auto kn = createChooseKfromN(xx.begin(),xx.end(),2);
int counter = 0;
do {
for (auto it = kn.begin();it != kn.end();it++){
std::cout << (**it).first << "\t";
}
std::cout << "\n";
counter++;
} while(kn.increment());
std::cout << "counter = " << counter << "\n";
}
...我收到运行时错误。使用向量时,我得到正确的输出(另请参阅here):
A A
B A
C A
B B
C B
C C
THIS IS NEVER REACHED FOR A MAP !!
counter = 6
为什么std::map
与std::vector
一起使用时会中断?
答案 0 :(得分:2)
Valgrind报道
==32738== Invalid read of size 8
==32738== at 0x109629: ChooseKfromN<std::_Rb_tree_iterator<std::pair<int const, int> > >::increment() (42559588.cpp:17)
==32738== by 0x108EFE: main (42559588.cpp:43)
==32738== Address 0x5a84d70 is 0 bytes after a block of size 16 alloc'd
==32738== at 0x4C2C21F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32738== by 0x10B21B: __gnu_cxx::new_allocator<std::_Rb_tree_iterator<std::pair<int const, int> > >::allocate(unsigned long, void const*) (new_allocator.h:104)
==32738== by 0x10B113: std::allocator_traits<std::allocator<std::_Rb_tree_iterator<std::pair<int const, int> > > >::allocate(std::allocator<std::_Rb_tree_iterator<std::pair<int const, int> > >&, unsigned long) (alloc_traits.h:416)
看第17行,就在这里:
if (it != combo.end()){
auto next = it;
next++;
auto nexit = (*next); // Line 17
nexit++;
如果next
== combo.end()
,则*next
是无效的引用。
答案 1 :(得分:1)
使用位图方法修复代码(请参阅definition)
我正在维护2个向量,一个是我们可以置换的启用索引的位图,另一个是容器中项目的引用向量。
我还提供了模板emit()
函数,因此相同的通用代码可以在地图,矢量,集合,无序映射等上运行。
#include <iostream>
#include <map>
#include <vector>
#include <functional>
#include <iterator>
template <typename Iter>
struct ChooseKfromN
{
using iterator_type = Iter;
using value_type = typename std::iterator_traits<iterator_type>::value_type;
using result_type = std::vector<std::reference_wrapper<const value_type>>;
result_type values_;
std::vector<bool> bitset_;
int k_;
ChooseKfromN(Iter first,Iter last,int k)
: values_(first, last)
, bitset_(values_.size() - k, 0)
, k_(k)
{
std::reverse(values_.begin(), values_.end());
bitset_.resize(values_.size(), 1);
}
result_type& get(result_type& target) const
{
target.clear();
for (std::size_t i = bitset_.size() ; i ; ) {
--i;
if (bitset_[i]) {
target.push_back(values_[i]);
}
}
return target;
}
bool increment(){
return std::next_permutation(bitset_.begin(), bitset_.end());
}
};
template <typename T>
ChooseKfromN<T> createChooseKfromN(T first,T last,int k) { return ChooseKfromN<T>(first,last,k); }
template<class T>
std::ostream& emit_key(std::ostream& os, const T& t)
{
return os << t;
}
template<class K, class V>
std::ostream& emit_key(std::ostream& os, const std::pair<const K, V>& kv)
{
return os << kv.first;
}
template<class Container>
void test(Container const& c)
{
auto kn = createChooseKfromN(c.begin(),c.end(),2);
using ChooserType = decltype(kn);
using ResultType = typename ChooserType::result_type;
int counter = 0;
ResultType result_buffer;
do {
kn.get(result_buffer);
for (auto&& ref : result_buffer)
{
emit_key(std::cout, ref.get()) << '\t';
}
std::cout << "\n";
counter++;
} while(kn.increment());
std::cout << "counter = " << counter << "\n";
}
int main(){
std::map<int,int> xx;
xx[1] = 1;
xx[2] = 2;
xx[3] = 3;
xx[4] = 4;
std::vector<std::string> yy = {"A","B","C"};
test(xx);
test(yy);
}
预期产出:
1 2
1 3
2 3
1 4
2 4
3 4
counter = 6
A B
A C
B C
counter = 3