error deleting item from list after passing through function - c++

I'm having a bit of trouble understanding what's happening when I try to delete an element from a list in this program i'm working on.
#include <cmath>
#include <cstdio>
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int findHigherSkillLevel(int skillLevel, list<int>::iterator *it, list<int> &list) {
if (it == NULL) return 0;
if (**it == (skillLevel + 1)) {
it = list.erase(it);
return 1 + findHigherSkillLevel(**it, it, list) + findHigherSkillLevel(**it, --it, list);
}
return 0;
}
int findLowerSkillLevel(int skillLevel, list<int>::iterator *it, list<int> &list) {
if (it == NULL) return 0;
if (**it == (skillLevel - 1)) {
it = list.erase(it);
return 1 + findLowerSkillLevel(**it, it, list) + findLowerSkillLevel(**it, --it, list);
}
return 0;
}
int findGroupsSizes(int skillLevel, list<int>::iterator *it, list<int> &list) {
if (it == NULL) return 0;
int groupSize = 1;
it = list.erase(it);
groupSize += findHigherSkillLevel(**it, it, list) + findLowerSkillLevel(**it, it, list);
return groupSize;
}
int main() {
int t; // the number of test cases
cin >> t;
vector<list<int> > skillLevels(t, list<int>());
// input for each test case
for (int i = 0; i < t; i++) {
int n; // number of students for this test case
cin >> n;
// initialize the list for this test case
for (int j = 0; j < n; j++) {
int skillLevel;
cin >> skillLevel;
skillLevels[i].push_back(skillLevel);
}
}
// recursively scan lists for smallest teams
for (int i = 0; i < t; i++) {
int minGroupNumber = skillLevels[i].size();
list<int>::iterator iterator = skillLevels[i].begin();
int skillLevel = skillLevels[i].front();
while (!skillLevels[i].empty()) {
int currentGroupSize = findGroupsSizes(skillLevel, &iterator, skillLevels[i]);
if (currentGroupSize < minGroupNumber)
minGroupNumber = currentGroupSize;
skillLevels[i].pop_front();
}
cout << minGroupNumber << endl;
}
return 0;
}
I already know that what's causing the error trying to call the "erase" function like this:
it = list.erase(it);
Which I typed in bold in the code. I don't understand why it's giving me the following output, since from what I understand erase() just needs an iterator to the location of the list to be deleted?:
teamFormation.cpp: In function ‘int findHigherSkillLevel(int, std::list<int>::iterator*, std::list<int>&)’:
teamFormation.cpp:13:24: error: no matching function for call to ‘std::list<int>::erase(std::list<int>::iterator*&)’
it = *list.erase(it);
^
teamFormation.cpp:13:24: note: candidates are:
In file included from /usr/include/c++/4.8/list:64:0,
from teamFormation.cpp:3:
/usr/include/c++/4.8/bits/list.tcc:108:5: note: std::list<_Tp, _Alloc>::iterator std::list<_Tp, _Alloc>::erase(std::list<_Tp, _Alloc>::iterator) [with _Tp = int; _Alloc = std::allocator<int>; std::list<_Tp, _Alloc>::iterator = std::_List_iterator<int>]
list<_Tp, _Alloc>::
^
/usr/include/c++/4.8/bits/list.tcc:108:5: note: no known conversion for argument 1 from ‘std::list<int>::iterator* {aka std::_List_iterator<int>*}’ to ‘std::list<int>::iterator {aka std::_List_iterator<int>}’
In file included from /usr/include/c++/4.8/list:63:0,
from teamFormation.cpp:3:
/usr/include/c++/4.8/bits/stl_list.h:1193:7: note: std::list<_Tp, _Alloc>::iterator std::list<_Tp, _Alloc>::erase(std::list<_Tp, _Alloc>::iterator, std::list<_Tp, _Alloc>::iterator) [with _Tp = int; _Alloc = std::allocator<int>; std::list<_Tp, _Alloc>::iterator = std::_List_iterator<int>]
erase(iterator __first, iterator __last)
^
/usr/include/c++/4.8/bits/stl_list.h:1193:7: note: candidate expects 2 arguments, 1 provided
teamFormation.cpp: In function ‘int findLowerSkillLevel(int, std::list<int>::iterator*, std::list<int>&)’:
teamFormation.cpp:24:24: error: no matching function for call to ‘std::list<int>::erase(std::list<int>::iterator*&)’
it = *list.erase(it);
^
teamFormation.cpp:24:24: note: candidates are:
In file included from /usr/include/c++/4.8/list:64:0,
from teamFormation.cpp:3:
/usr/include/c++/4.8/bits/list.tcc:108:5: note: std::list<_Tp, _Alloc>::iterator std::list<_Tp, _Alloc>::erase(std::list<_Tp, _Alloc>::iterator) [with _Tp = int; _Alloc = std::allocator<int>; std::list<_Tp, _Alloc>::iterator = std::_List_iterator<int>]
list<_Tp, _Alloc>::
^
/usr/include/c++/4.8/bits/list.tcc:108:5: note: no known conversion for argument 1 from ‘std::list<int>::iterator* {aka std::_List_iterator<int>*}’ to ‘std::list<int>::iterator {aka std::_List_iterator<int>}’
In file included from /usr/include/c++/4.8/list:63:0,
from teamFormation.cpp:3:
/usr/include/c++/4.8/bits/stl_list.h:1193:7: note: std::list<_Tp, _Alloc>::iterator std::list<_Tp, _Alloc>::erase(std::list<_Tp, _Alloc>::iterator, std::list<_Tp, _Alloc>::iterator) [with _Tp = int; _Alloc = std::allocator<int>; std::list<_Tp, _Alloc>::iterator = std::_List_iterator<int>]
erase(iterator __first, iterator __last)
^
/usr/include/c++/4.8/bits/stl_list.h:1193:7: note: candidate expects 2 arguments, 1 provided
teamFormation.cpp: In function ‘int findGroupsSizes(int, std::list<int>::iterator*, std::list<int>&)’:
teamFormation.cpp:35:22: error: no matching function for call to ‘std::list<int>::erase(std::list<int>::iterator*&)’
it = *list.erase(it);
^
teamFormation.cpp:35:22: note: candidates are:
In file included from /usr/include/c++/4.8/list:64:0,
from teamFormation.cpp:3:
/usr/include/c++/4.8/bits/list.tcc:108:5: note: std::list<_Tp, _Alloc>::iterator std::list<_Tp, _Alloc>::erase(std::list<_Tp, _Alloc>::iterator) [with _Tp = int; _Alloc = std::allocator<int>; std::list<_Tp, _Alloc>::iterator = std::_List_iterator<int>]
list<_Tp, _Alloc>::
^
/usr/include/c++/4.8/bits/list.tcc:108:5: note: no known conversion for argument 1 from ‘std::list<int>::iterator* {aka std::_List_iterator<int>*}’ to ‘std::list<int>::iterator {aka std::_List_iterator<int>}’
In file included from /usr/include/c++/4.8/list:63:0,
from teamFormation.cpp:3:
/usr/include/c++/4.8/bits/stl_list.h:1193:7: note: std::list<_Tp, _Alloc>::iterator std::list<_Tp, _Alloc>::erase(std::list<_Tp, _Alloc>::iterator, std::list<_Tp, _Alloc>::iterator) [with _Tp = int; _Alloc = std::allocator<int>; std::list<_Tp, _Alloc>::iterator = std::_List_iterator<int>]
erase(iterator __first, iterator __last)
^
/usr/include/c++/4.8/bits/stl_list.h:1193:7: note: candidate expects 2 arguments, 1 provided

The error message is self-explanatory: at that point it is not a std::list::iterator, it's actually an std::list::iterator*. You must dereference the pointer (as you did just on the previous line).

Related

no match for call in STL

i am storing pointer to object in vector(STL). and i am performing some operation based on Account number , i am using lambda function to solve it .
But I am getting some error .
How to fixed it ???
class BankingSystem {
vector <Account *> vobject;
public :
BankingSystem();
void Create_new_Account();
void Account_info();
void Get_All_Account_info();
void Withdraw();
};
void BankingSystem :: Account_info()
{
long int ACC_NUMBER;
cout << "Enter AccountNumber : " <<endl;
cin >> ACC_NUMBER;
vector<Account*> :: iterator mAccount = std::find_if(vobject.begin(), vobject.end(),
[&ACC_NUMBER](const Account& a) {
// acc_number is maybe called something else in
// your Account class.
return a.Acc_holder.Account_number == ACC_NUMBER;
});
if(mAccount != vobject.end())
{
cout << (*mAccount)->Acc_holder.Account_number << endl;
cout << (*mAccount)->Acc_holder.aadharNo << endl;
vobject.erase(mAccount); // not "delete mAccount;"
}
}
This is an error . i am not getting what exactly the error is ? please elaborate it .
In file included from /usr/include/c++/7/bits/stl_algobase.h:71:0,
from /usr/include/c++/7/bits/char_traits.h:39,
from /usr/include/c++/7/ios:40,
from /usr/include/c++/7/ostream:38,
from /usr/include/c++/7/iostream:39,
from /home/pankaj/BANK/./include/stdheader.h:4,
from /home/pankaj/BANK/src/bankingSystem.cpp:1:
/usr/include/c++/7/bits/predefined_ops.h: In instantiation of ‘bool __gnu_cxx::__ops::_Iter_pred<_Predicate>::operator()(_Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<account**, std::vector<account*> >; _Predicate = BankingSystem::Account_info()::<lambda(Account&)>]’:
/usr/include/c++/7/bits/stl_algo.h:120:14: required from ‘_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<account**, std::vector<account*> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<BankingSystem::Account_info()::<lambda(Account&)> >]’
/usr/include/c++/7/bits/stl_algo.h:161:23: required from ‘_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator<account**, std::vector<account*> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<BankingSystem::Account_info()::<lambda(Account&)> >]’
/usr/include/c++/7/bits/stl_algo.h:3932:28: required from ‘_IIter std::find_if(_IIter, _IIter, _Predicate) [with _IIter = __gnu_cxx::__normal_iterator<account**, std::vector<account*> >; _Predicate = BankingSystem::Account_info()::<lambda(Account&)>]’
/home/pankaj/BANK/src/bankingSystem.cpp:40:35: required from here
/usr/include/c++/7/bits/predefined_ops.h:283:11: error: no match for call to ‘(BankingSystem::Account_info()::<lambda(Account&)>) (account*&)’
{ return bool(_M_pred(*__it)); }
^~~~~~~~~~~~~~~~~~~~
/home/pankaj/BANK/src/bankingSystem.cpp:36:58: note: candidate: BankingSystem::Account_info()::<lambda(Account&)>
[&ACC_NUMBER](Account& a) {
^
/home/pankaj/BANK/src/bankingSystem.cpp:36:58: note: no known conversion for argument 1 from ‘account*’ to ‘Account& {aka account&}’
Looking at this line of your code:
vector<Account*> :: iterator mAccount = std::find_if(vobject.begin(), vobject.end(),
[&ACC_NUMBER](const Account& a) {
Your lambda should accept an Account *, not an Account, because you are iterating over a std::vector<Account *>.

open ofstream as class attribute

I would like to add an open ofstream as a class (Barcode) attribute. The goal is to implement several Barcodes in my main() that will each be able to write into a specific file. Also, I decided to stock all the barcodes in a vector, which belongs to a Barcodes class, although it is maybe not useful.
Here is my code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sys/stat.h>
using namespace std;
class Barcode {
public:
// Constructor
Barcode(string bcName, string bcSeq, string end, string const & fileName):
m_bcName(bcName), m_bcSeq(bcSeq), m_end(end), m_ofStream(fileName.c_str(), ios::app) {}
// Getters
string getBCName() const {
return m_bcName;
}
string getBCSeq() const {
return m_bcSeq;
}
//setter
void reportRead(string toReport) {
m_ofStream << toReport;
}
private:
string m_bcName;
string m_bcSeq;
string m_end;
ofstream m_ofStream;
};
class Barcodes {
public:
// Constructor
Barcodes(string barcodesFile, string end): m_barcodesFile(barcodesFile), m_end(end) {
initializeBarcodes();
}
// Getters
vector<Barcode> getBCs() {
return m_barcodes;
}
// Other
void initializeBarcodes() {
ifstream flow(m_barcodesFile);
if(!flow) {
cerr << "ERROR: Could'n find the \"barcode.txt\" file." << endl;
}
else {
string line, name, seq;
// parse each line of the barcode file
while(getline(flow, line)) {
//get the name and sequence of the barcodes
name = line.substr(0, 4);
seq = line.substr(5, 6);
//create the corresponding Barcode
string fileName = "Demultiplexed_Reads/" + name + "." + m_end + ".fastq";
Barcode bc(name, seq, m_end, fileName);
//add them in the corresponding vector
m_barcodes.push_back(bc);
}
}
}
private:
string m_barcodesFile;
string m_end;
vector<Barcode> m_barcodes;
};
int main(int argc, char* argv[]) {
//Create a new "Demultiplexed_Reads" folder
system("rm -rf Demultiplexed_Reads");
if(mkdir("Demultiplexed_Reads", 0755) != 0) {
cerr << "ERROR: Couldn't create the Demultiplexed folder." << endl;
return 1;
}
else {
// Get the files to demultiplex
string f1 = argv[1];
string f2 = argv[2];
// Generate the vectors of barcodes
Barcodes bcs1("barcodes.txt", "end1");
vector<Barcode> barcodes1(bcs1.getBCs());
Barcodes bcs2("barcodes.txt", "end2");
vector<Barcode> barcodes2(bcs2.getBCs());
// Demultiplex the reads of the end1
Demultiplexer dm1(f1, barcodes1, "end1");
dm1.demultiplex();
cout << "Reads of end1 demultiplexed" << endl;
// Demultiplex the reads of the end2
Demultiplexer dm2(f2, barcodes2, "end2");
dm2.demultiplex();
cout << "Reads of end2 demultiplexed" << endl;
return 0;
}
}
However, I encounter errors that I don't understand about deleted methods when I am trying to compile g++ --std=c++11 myProg.cpp -o myProg:
In file included from /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h:33:0,
from /usr/include/c++/5/bits/allocator.h:46,
from /usr/include/c++/5/string:41,
from /usr/include/c++/5/bits/locale_classes.h:40,
from /usr/include/c++/5/bits/ios_base.h:41,
from /usr/include/c++/5/ios:42,
from /usr/include/c++/5/ostream:38,
from /usr/include/c++/5/iostream:39,
from Demultiplex.cpp:1:
/usr/include/c++/5/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = Barcode; _Args = {const Barcode&}; _Tp = Barcode]’:
/usr/include/c++/5/bits/alloc_traits.h:530:4: required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = Barcode; _Args = {const Barcode&}; _Tp = Barcode; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<Barcode>]’
/usr/include/c++/5/bits/stl_vector.h:917:30: required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = Barcode; _Alloc = std::allocator<Barcode>; std::vector<_Tp, _Alloc>::value_type = Barcode]’
Demultiplex.cpp:85:44: required from here
/usr/include/c++/5/ext/new_allocator.h:120:4: error: use of deleted function ‘Barcode::Barcode(const Barcode&)’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^
Demultiplex.cpp:18:7: note: ‘Barcode::Barcode(const Barcode&)’ is implicitly deleted because the default definition would be ill-formed:
class Barcode {
^
Demultiplex.cpp:18:7: error: use of deleted function ‘std::basic_ofstream<_CharT, _Traits>::basic_ofstream(const std::basic_ofstream<_CharT, _Traits>&) [with _CharT = char; _Traits = std::char_traits<char>]’
In file included from Demultiplex.cpp:2:0:
/usr/include/c++/5/fstream:723:7: note: declared here
basic_ofstream(const basic_ofstream&) = delete;
^
In file included from /usr/include/c++/5/vector:62:0,
from Demultiplex.cpp:4:
/usr/include/c++/5/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = Barcode; _Args = {const Barcode&}]’:
/usr/include/c++/5/bits/stl_uninitialized.h:75:18: required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const Barcode*, std::vector<Barcode> >; _ForwardIterator = Barcode*; bool _TrivialValueTypes = false]’
/usr/include/c++/5/bits/stl_uninitialized.h:126:15: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const Barcode*, std::vector<Barcode> >; _ForwardIterator = Barcode*]’
/usr/include/c++/5/bits/stl_uninitialized.h:281:37: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const Barcode*, std::vector<Barcode> >; _ForwardIterator = Barcode*; _Tp = Barcode]’
/usr/include/c++/5/bits/stl_vector.h:322:31: required from ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = Barcode; _Alloc = std::allocator<Barcode>]’
Demultiplex.cpp:63:20: required from here
/usr/include/c++/5/bits/stl_construct.h:75:7: error: use of deleted function ‘Barcode::Barcode(const Barcode&)’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
Does anybody know what the problem is ?
Thank you so much !
So I found a way to overcome my problem so I just write the solution I used here in case it would be useful for somebody.
Finally, I created a vector of ofstreams in the method that write into output files instead of putting the streams in the objects. I did it just before the loop that reads ans sorts lines from the input file.
As you said, the trick is no to try to copy the stream since it is not possible. But their reference can be moved into the vector. So I used the move function, which is in the standard since C++11:
ofstream ofs(fileName);
ofStreams.push_back(move(ofs));
I worked for me and allowed my program to be way faster than opening a stream and closing it for every line that I need to sort.

Error using std::set to implement a sparse 3D grid

I'm trying to implement a sparse 3D grid with std::set container, but I can't understand the error returned from the compiler, this is the minimal example I'm trying to run:
#include <iostream>
#include <vector>
#include <limits>
#include <set>
#include <Eigen/Core>
using namespace std;
class Cell {
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
Cell(const Eigen::Vector3i idx=Eigen::Vector3i::Zero()):_idx(idx) {
_center = Eigen::Vector3f::Zero();
_parent = 0;
_distance = std::numeric_limits<int>::max();
}
inline bool operator < (const Cell& c){
for (int i=0; i<3; i++){
if (_idx[i]<c._idx[i])
return true;
if (_idx[i]>c._idx[i])
return false;
}
return false;
}
inline bool operator == (const Cell& c) { return c._idx == _idx;}
private:
Eigen::Vector3i _idx;
Eigen::Vector3f _center;
vector<Eigen::Vector3f> _points;
Cell* _parent;
size_t _closest_point;
float _distance;
int _tag;
};
int main(int argc, char* argv[]) {
set<Cell> grid;
float max = 1, min = -1;
int dim = 5;
float delta = (max-min)/(dim-1);
for(int k = 0; k < dim; k++)
for(int j = 0; j < dim; j++)
for(int i = 0; i < dim; i++)
grid.insert(Cell(Eigen::Vector3i(i,j,k)));
return 0;
}
and this is the compiler error:
In file included from /usr/include/c++/4.8/string:48:0,
from /usr/include/c++/4.8/bits/locale_classes.h:40,
from /usr/include/c++/4.8/bits/ios_base.h:41,
from /usr/include/c++/4.8/ios:42,
from /usr/include/c++/4.8/ostream:38,
from /usr/include/c++/4.8/iostream:39,
from /home/dede/build/sparse_grid/main.cpp:1: /usr/include/c++/4.8/bits/stl_function.h: In instantiation of 'bool
std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp =
Cell]': /usr/include/c++/4.8/bits/stl_tree.h:1324:11: required from
'std::pair
std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare,
_Alloc>::_M_get_insert_unique_pos(const key_type&) [with _Key = Cell; _Val = Cell; _KeyOfValue = std::_Identity; _Compare = std::less; _Alloc = std::allocator; std::_Rb_tree<_Key,
_Val, _KeyOfValue, _Compare, _Alloc>::key_type = Cell]' /usr/include/c++/4.8/bits/stl_tree.h:1377:47: required from
'std::pair, bool> std::_Rb_tree<_Key,
_Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(_Arg&&) [with _Arg = Cell; _Key = Cell; _Val = Cell; _KeyOfValue = std::_Identity; _Compare = std::less; _Alloc =
std::allocator]' /usr/include/c++/4.8/bits/stl_set.h:472:40:
required from 'std::pair, _Compare, typename
_Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(std::set<_Key, _Compare, _Alloc>::value_type&&) [with _Key = Cell; _Compare = std::less; _Alloc = std::allocator; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename
_Alloc::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator; std::set<_Key, _Compare,
_Alloc>::value_type = Cell]' /home/dede/build/sparse_grid/main.cpp:53:57: required from here
/usr/include/c++/4.8/bits/stl_function.h:235:20: error: passing 'const
Cell' as 'this' argument of 'bool Cell::operator<(const Cell&)'
discards qualifiers [-fpermissive]
{ return __x < __y; }
^ make[2]: * [CMakeFiles/sparse_grid.dir/main.cpp.o] Error 1 make[1]: *
[CMakeFiles/sparse_grid.dir/all] Error 2 make: *** [all] Error 2
I would really appreciate if someone could tell me what I'm doing wrong.
Thanks,
Federico
You should declare your boolean operator functions as const members:
inline bool operator < (const Cell& c) const {
// ^^^^^
for (int i=0; i<3; i++){
if (_idx[i]<c._idx[i])
return true;
if (_idx[i]>c._idx[i])
return false;
}
return false;
}
inline bool operator == (const Cell& c) const { return c._idx == _idx;}
// ^^^^^
Otherwise these cannot be used with rvalue objects of Cell.
You have defined operator < in Cell, but the error says it wants bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Cell]. Notice you should make your member function const.
You could provide a non-member function for less, which can use your member function, once the it is const.
bool operator <(const Cell &a, const Cell &b)
{
return a < b;
}
However, std::less will provide this for you, provided your member function is const.
You have declared your Parameters for > and == operators overloads as const and you are passing a temporary.
Just create a temporary Object of Cell within the loop and insert it in cell
Do it like this :
for(int k = 0; k < dim; k++)
for(int j = 0; j < dim; j++)
for(int i = 0; i < dim; i++)
{
Eigen::Vector3i(i,j,k) eigenVec;
Cell cell(eigenVec);
grid.insert(cell);
}
Your compilation should succeed.

Implementing BFS using C++

I am trying to implement BFS in C++, Here is the code.
#include <iostream>
#include <list>
#include <string>
#include <limits>
#include <map>
int infinity=std::numeric_limits<int>::max();
struct Node{
int value;
int distance;
std::string color;
Node(int val):
value(val),
distance(infinity),
color("white")
{}
};
//using AdjList = std::map<Node*,std::list<Node*>>;
typedef std::map<Node*,std::list<Node*>> AdjList;
AdjList create_graph()
{
Node* n1 = new Node(1);
Node* n2 = new Node(2);
Node* n3 = new Node(3);
Node* n4 = new Node(4);
Node* n5 = new Node(5);
Node* n6 = new Node(6);
Node* n7 = new Node(7);
Node* n8 = new Node(8);
AdjList m;
m[n1] = {n2, n5};
m[n2] = {n1, n6};
m[n3] = {n4, n6, n7};
m[n4] = {n3, n7, n8};
m[n5] = {n1};
m[n6] = {n2, n3, n7};
m[n7] = {n3, n4, n6, n8};
m[n8] = {n4, n7};
return m;
}
void bfs(const AdjList& m, Node* n1)
{
std::list<Node*> queue;
queue.push_back(n1);
unsigned count = 0;
while (!queue.empty())
{
auto n = queue.front();
std::cout << n->value << std::endl;
queue.pop_front();
std::cout << *(m[n].begin()) << std::endl;
for(auto it = m[n].begin(); it != m[n].end(); ++it)
{
if ((*it)->color != "black")
queue.push_back(*it);
}
n->color = "black";
n->distance = count;
++count;
}
}
On trying to compile with gcc, I receive the following error messages.
bfs.cpp: In function ‘void bfs(const AdjList&, Node*)’:
bfs.cpp:59:27: error: passing ‘const AdjList {aka const std::map<Node*, std::list<Node*> >}’ as ‘this’ argument of ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = Node*; _Tp = std::list<Node*>; _Compare = std::less<Node*>; _Alloc = std::allocator<std::pair<Node* const, std::list<Node*> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = std::list<Node*>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = Node*]’ discards qualifiers [-fpermissive]
std::cout << *(m[n].begin()) << std::endl;
^
bfs.cpp:60:20: error: passing ‘const AdjList {aka const std::map<Node*, std::list<Node*> >}’ as ‘this’ argument of ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = Node*; _Tp = std::list<Node*>; _Compare = std::less<Node*>; _Alloc = std::allocator<std::pair<Node* const, std::list<Node*> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = std::list<Node*>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = Node*]’ discards qualifiers [-fpermissive]
for(auto it = m[n].begin(); it != m[n].end(); ++it)
^
bfs.cpp:60:40: error: passing ‘const AdjList {aka const std::map<Node*, std::list<Node*> >}’ as ‘this’ argument of ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = Node*; _Tp = std::list<Node*>; _Compare = std::less<Node*>; _Alloc = std::allocator<std::pair<Node* const, std::list<Node*> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = std::list<Node*>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = Node*]’ discards qualifiers [-fpermissive]
for(auto it = m[n].begin(); it != m[n].end(); ++it)
I am not sure what is wrong. Please point out the mistake.
std::map::operator[] is non-const because it will insert elements if needed:
int main()
{
std::map<std::string, std::string> m;
m["new element"] = "1";
}
The problem is that m is a const AdjList&, on which you cannot call non-const member functions. You can use std::map::find() instead:
auto itor = m.find(n);
if (itor != m.end())
std::cout << *(m->second.begin()) << std::endl;
Two C++11 features will make your life much easier
the at() const function for maps, which is like [] but throws an out of range exception if the key is not there, instead of adding a new item to the map.
the for loop over containers
So :
for (auto it : m.at(n)) {
if (it->color != "black")
queue.push_back(it);
}

Sorting an array of int[2] does not compile

I have a data array with 2*N ints, representing pairs, that is for even i=0,2,4,...,2*N (pairs[i], pairs[i+1]) is such a pair. The data is formatted like this because I use Matlab's mex library. I do:
int N=5;
int data[10] = {1,2,3,4,5,6,7,8,9,10};
struct Pair { int first; int second; };
Pair * pairs = (Pair *)data;
but the problem would be that there is no way to guarantee that Pair aligns as two sizeof(ints) in order first, second. See: Is the member field order of a class "stable"?
I don't want to process and copy all data into a new array, since it should not be necessary, and I need (as far as I can see) to use
typedef int Pair[2];
to be sure that it aligns correctly (no trailing garbage bytes, etc). if I then want to sort the pairs according to the first element, I could do:
#include <iostream>
#include <algorithm>
typedef int Pair[2];
int compare(Pair n1, Pair n2) { return n1[0] < n2[0]; }
int main() {
int N=5;
int data[10] = {1,2, 7,8, 13,14, 4,5, 10,11};
Pair *pairs = (Pair *)((void *)data);
std::cout << "unsorted" << std::endl;
for(int i=0; i<N;++i) std::cout << i << ": (" << pairs[i][0] << ", " << pairs[i][1] << ")" << std::endl;
std::sort(data, data+N, compare);
std::cout << "sorted" << std::endl;
for(int i=0; i<N;++i) std::cout << i << ": (" << pairs[i][0] << ", " << pairs[i][1] << ")" << std::endl;
return 0;
}
see: http://ideone.com/VyBUvc
I could summarize the error message as error: array must be initialized with a brace-enclosed initializer, see below for the complete message. It is caused by the std::sort call.
I wrapped the Pair typedef in a union here ( http://ideone.com/TVmEeZ ), and that seems to work. Why does c++ (or std::sort) not see int[2] in a similar way as a union?
Complete compiler output:
In file included from /usr/include/c++/4.8/bits/stl_pair.h:59:0,
from /usr/include/c++/4.8/bits/stl_algobase.h:64,
from /usr/include/c++/4.8/bits/char_traits.h:39,
from /usr/include/c++/4.8/ios:40,
from /usr/include/c++/4.8/ostream:38,
from /usr/include/c++/4.8/iostream:39,
from prog.cpp:1:
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of ‘void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = int (*)[2]; _Compare = bool (*)(int*, int*)]’:
/usr/include/c++/4.8/bits/stl_algo.h:2250:70: required from ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = int (*)[2]; _Compare = bool (*)(int*, int*)]’
/usr/include/c++/4.8/bits/stl_algo.h:5514:55: required from ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = int (*)[2]; _Compare = bool (*)(int*, int*)]’
prog.cpp:16:35: required from here
/usr/include/c++/4.8/bits/stl_algo.h:2186:11: error: array must be initialized with a brace-enclosed initializer
__val = _GLIBCXX_MOVE(*__i);
^
In file included from /usr/include/c++/4.8/algorithm:62:0,
from prog.cpp:2:
/usr/include/c++/4.8/bits/stl_algo.h:2188:17: error: invalid array assignment
*__first = _GLIBCXX_MOVE(__val);
^
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of ‘_RandomAccessIterator std::__unguarded_partition(_RandomAccessIterator, _RandomAccessIterator, const _Tp&, _Compare) [with _RandomAccessIterator = int (*)[2]; _Tp = int [2]; _Compare = bool (*)(int*, int*)]’:
/usr/include/c++/4.8/bits/stl_algo.h:2319:78: required from ‘_RandomAccessIterator std::__unguarded_partition_pivot(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = int (*)[2]; _Compare = bool (*)(int*, int*)]’
/usr/include/c++/4.8/bits/stl_algo.h:2360:62: required from ‘void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size, _Compare) [with _RandomAccessIterator = int (*)[2]; _Size = int; _Compare = bool (*)(int*, int*)]’
/usr/include/c++/4.8/bits/stl_algo.h:5513:44: required from ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = int (*)[2]; _Compare = bool (*)(int*, int*)]’
prog.cpp:16:35: required from here
/usr/include/c++/4.8/bits/stl_algo.h:2287:35: error: invalid conversion from ‘const int*’ to ‘int*’ [-fpermissive]
while (__comp(*__first, __pivot))
^
/usr/include/c++/4.8/bits/stl_algo.h:2290:34: error: invalid conversion from ‘const int*’ to ‘int*’ [-fpermissive]
while (__comp(__pivot, *__last))
^
In file included from /usr/include/c++/4.8/bits/stl_pair.h:59:0,
from /usr/include/c++/4.8/bits/stl_algobase.h:64,
from /usr/include/c++/4.8/bits/char_traits.h:39,
from /usr/include/c++/4.8/ios:40,
from /usr/include/c++/4.8/ostream:38,
from /usr/include/c++/4.8/iostream:39,
from prog.cpp:1:
/usr/include/c++/4.8/bits/stl_heap.h: In instantiation of ‘void std::make_heap(_RAIter, _RAIter, _Compare) [with _RAIter = int (*)[2]; _Compare = bool (*)(int*, int*)]’:
/usr/include/c++/4.8/bits/stl_algo.h:1970:47: required from ‘void std::__heap_select(_RandomAccessIterator, _RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = int (*)[2]; _Compare = bool (*)(int*, int*)]’
/usr/include/c++/4.8/bits/stl_algo.h:5363:59: required from ‘void std::partial_sort(_RAIter, _RAIter, _RAIter, _Compare) [with _RAIter = int (*)[2]; _Compare = bool (*)(int*, int*)]’
/usr/include/c++/4.8/bits/stl_algo.h:2355:68: required from ‘void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size, _Compare) [with _RandomAccessIterator = int (*)[2]; _Size = int; _Compare = bool (*)(int*, int*)]’
/usr/include/c++/4.8/bits/stl_algo.h:5513:44: required from ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = int (*)[2]; _Compare = bool (*)(int*, int*)]’
prog.cpp:16:35: required from here
/usr/include/c++/4.8/bits/stl_heap.h:446:25: error: array must be initialized with a brace-enclosed initializer
_ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
^
/usr/include/c++/4.8/bits/stl_heap.h: In instantiation of ‘void std::__pop_heap(_RandomAccessIterator, _RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = int (*)[2]; _Compare = bool (*)(int*, int*)]’:
/usr/include/c++/4.8/bits/stl_algo.h:1973:50: required from ‘void std::__heap_select(_RandomAccessIterator, _RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = int (*)[2]; _Compare = bool (*)(int*, int*)]’
/usr/include/c++/4.8/bits/stl_algo.h:5363:59: required from ‘void std::partial_sort(_RAIter, _RAIter, _RAIter, _Compare) [with _RAIter = int (*)[2]; _Compare = bool (*)(int*, int*)]’
/usr/include/c++/4.8/bits/stl_algo.h:2355:68: required from ‘void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size, _Compare) [with _RandomAccessIterator = int (*)[2]; _Size = int; _Compare = bool (*)(int*, int*)]’
/usr/include/c++/4.8/bits/stl_algo.h:5513:44: required from ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = int (*)[2]; _Compare = bool (*)(int*, int*)]’
prog.cpp:16:35: required from here
/usr/include/c++/4.8/bits/stl_heap.h:339:28: error: array must be initialized with a brace-enclosed initializer
_ValueType __value = _GLIBCXX_MOVE(*__result);
^
In file included from /usr/include/c++/4.8/bits/stl_algo.h:61:0,
from /usr/include/c++/4.8/algorithm:62,
from prog.cpp:2:
/usr/include/c++/4.8/bits/stl_heap.h:340:17: error: invalid array assignment
*__result = _GLIBCXX_MOVE(*__first);
^
std::sort(data, data+N, compare);
You are sorting data, not pairs. That said, your new approach is still undefined behaviour, and thus not guaranteed to work1. You are essentially trying to fit a square peg into a round hole. If you want to use std::sort, present valid data – which means copying in your case, or writing a custom iterator which treats an array as a collection of consecutive pairs.
1 That’s a humungous understatement. – Do not do this.
Exchanging your array of two int for a std::pair<int,int> did the trick for me (live at ideone):
#include <iostream>
#include <algorithm>
#include <memory>
typedef std::pair<int,int> Pair;
bool compare(const Pair& i, const Pair& j) { return i.first < j.first; }
int main() {
const int N=5;
Pair pairs[N] = {{1,2}, {7,8}, {13,14}, {4,5}, {10,11}};
std::cout << "unsorted" << std::endl;
for(int i=0; i<N;++i) std::cout << i << ": (" << pairs[i].first << ", " << pairs[i].second << ")" << std::endl;
std::sort(pairs, pairs+N, compare);
std::cout << "sorted" << std::endl;
for(int i=0; i<N;++i) std::cout << i << ": (" << pairs[i].first << ", " << pairs[i].second << ")" << std::endl;
}
An alternative would be encapsulating the array of two int inside a struct. The problem in your code is that std::sort need an array of comparable (you fixed it with your compare function) and copy-or-move-assignable items (arrays are neither)
Maybe even better (less changes to your code) would be using std::array:
#include <iostream>
#include <algorithm>
#include <memory>
typedef std::array<int, 2> Pair;
bool compare(const Pair& i, const Pair& j) { return i[0] < j[0]; }
int main() {
const int N=5;
Pair pairs[N] = {1,2, 7,8, 13,14, 4,5, 10,11};
std::cout << "unsorted" << std::endl;
for(int i=0; i<N;++i) std::cout << i << ": (" << pairs[i][0] << ", " << pairs[i][1] << ")" << std::endl;
std::sort(pairs, pairs+N, compare);
std::cout << "sorted" << std::endl;
for(int i=0; i<N;++i) std::cout << i << ": (" << pairs[i][0] << ", " << pairs[i][1] << ")" << std::endl;
}