Unable to initialize threads vector - c++

I have implemented this simple C++11 Blocking Queue that I'd like to test. In order to test it, I initialize the following producer and consumer thread vectors with 10 producers and 10 consumers respectively.
#include <iostream>
#include <random>
#include <thread>
#include <vector>
#include "blockingqueue.h"
int main() {
// create a blocking queue with capacity 3
blocking_queue<int> queue(3);
uniform_int_distribution<> dis(1, 10);
random_device rd;
mt19937 gen(rd());
// create 10 producers
vector<thread> producers(10, thread([&] () {
cout << "attempting to produce a job ..." << endl;
int job = dis(gen);
queue.put(job);
cout << "produced job " << job << endl;
}));
// create 10 consumers
vector<thread> consumers(10, thread([&] () {
cout << "attempting to take a job ..." << endl;
int job = queue.take();
cout << "consumed job " << job << endl;
}));
// wait for all producers to complete
for(auto& thread : producers){
thread.join();
}
// wait for all consumers to complete
for(auto& thread : consumers){
thread.join();
}
return EXIT_SUCCESS;
}
However, I can't get it to compile with the following errors:
g++ -std=c++0x -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"src/cpp11showcase.d" -MT"src/cpp11showcase.o" -o "src/cpp11showcase.o" "../src/cpp11showcase.cpp"
In file included from /usr/include/c++/4.8/vector:62:0,
from ../src/cpp11showcase.cpp:13:
/usr/include/c++/4.8/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = std::thread; _Args = {const std::thread&}]’:
/usr/include/c++/4.8/bits/stl_uninitialized.h:187:48: required from ‘static void std::__uninitialized_fill_n<_TrivialValueType>::__uninit_fill_n(_ForwardIterator, _Size, const _Tp&) [with _ForwardIterator = std::thread*; _Size = long unsigned int; _Tp = std::thread; bool _TrivialValueType = false]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:224:35: required from ‘void std::uninitialized_fill_n(_ForwardIterator, _Size, const _Tp&) [with _ForwardIterator = std::thread*; _Size = long unsigned int; _Tp = std::thread]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:334:50: required from ‘void std::__uninitialized_fill_n_a(_ForwardIterator, _Size, const _Tp&, std::allocator<_Tp2>&) [with _ForwardIterator = std::thread*; _Size = long unsigned int; _Tp = std::thread; _Tp2 = std::thread]’
/usr/include/c++/4.8/bits/stl_vector.h:1215:32: required from ‘void std::vector<_Tp, _Alloc>::_M_fill_initialize(std::vector<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = std::thread; _Alloc = std::allocator<std::thread>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = std::thread]’
/usr/include/c++/4.8/bits/stl_vector.h:284:40: required from ‘std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = std::thread; _Alloc = std::allocator<std::thread>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = std::thread; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<std::thread>]’
../src/cpp11showcase.cpp:83:4: required from here
/usr/include/c++/4.8/bits/stl_construct.h:75:7: error: use of deleted function ‘std::thread::thread(const std::thread&)’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^
In file included from ../src/blockingqueue.h:13:0,
from ../src/cpp11showcase.cpp:18:
/usr/include/c++/4.8/thread:126:5: error: declared here
thread(const thread&) = delete;
^
make: *** [src/cpp11showcase.o] Error 1
UPDATE: it seems that the vector initialization doesn't like to capture the referenced variables by reference i.e. queue, dis and gen. The thread copy constructor has the method thread(const thread&) = delete; unavailable

// create 10 producers
vector<thread> producers(10, thread([&] () {
cout << "attempting to produce a job ..." << endl;
int job = dis(gen);
queue.put(job);
cout << "produced job " << job << endl;
}));
The constructor of std::vector will copy the std::thread 10 times, but you can't copy a std::thread, because its copy constructor is deleted.
Instead, you can use std::vector::emplace_back:
vector<thread> producers;
//Loop 10 times (for 10 threads)
for (std::size_t i = 0; i < 10; ++i)
produces.emplace_back([&] () {
cout << "attempting to take a job ..." << endl;
int job = queue.take();
cout << "consumed job " << job << endl;
});
I don't think there is a way to construct n elements in place in a std::vector, but you could put the loop in a function:
template<typename T>
void fillThread(std::vector<std::thread>& threads, std::size_t count, T func)
{
for (std::size_t i = 0; i < count; ++i)
threads.emplace_back(func);
}
You can then call it like so:
std::vector<std::thread> producers;
fillThread(producers, 10, [&] () {
cout << "attempting to take a job ..." << endl;
int job = queue.take();
cout << "consumed job " << job << endl;
});

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.

Compiling error when insert pair into set [duplicate]

This question already has answers here:
problems with c++ set container
(2 answers)
Closed 6 years ago.
I can't understand why g++ returns error like this:
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_pair.h: In function 鈥榖ool std::operator<(const std::pair<_T1, _T2>&, const std::pair<_T1, _T2>&) [with _T1 = int, _T2 = stop]鈥
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_function.h:227: instantiated from 鈥榖ool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = std::pair<int, stop>]鈥
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_tree.h:921: instantiated from 鈥榮td::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::insert_unique(const _Val&) [with _Key = std::pair<int, stop>, _Val = std::pair<int, stop>, _KeyOfValue = std::_Identity<std::pair<int, stop> >, _Compare = std::less<std::pair<int, stop> >, _Alloc = std::allocator<std::pair<int, stop> >]鈥
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_set.h:321: instantiated from 鈥榮td::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const _Key&) [with _Key = std::pair<int, stop>, _Compare = std::less<std::pair<int, stop> >, _Alloc = std::allocator<std::pair<int, stop> >]鈥
newGraph.cpp:48: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_pair.h:104: error: no match for 鈥榦perator<鈥in 鈥榑_x->std::pair<int, stop>::second < __y->std::pair<int, stop>::second鈥
Here is my code:
#include <iostream>
#include <vector>
#include <string>
#include <list>
#include <set>
#include <utility> // for pair
#include <algorithm>
#include <iterator>
const int max_weight = INT_MAX;
struct stop {
std::string name_stop;
int id_stop;
bool operator !=(const stop &rhs) const
{
return ((id_stop != rhs.id_stop) || (name_stop != rhs.name_stop));
}
};
struct neighbor {
stop target;
int weight;
neighbor(stop arg_target, int arg_weight) : target(arg_target), weight(arg_weight) { }
};
std::list<stop> dijkstraComputeAndGetShortestPaths(stop src,
stop dst,
std::vector< std::vector<neighbor> > &adj_list,
std::vector<int> &min_distance,
std::vector<stop> &previous)
{
stop fake_stop;
fake_stop.id_stop = INT_MAX;
fake_stop.name_stop = "Null";
std::list<stop> path;
int n = adj_list.size();
min_distance.clear();
min_distance.resize(n, max_weight);
min_distance[src.id_stop] = 0;
previous.clear();
previous.resize(n, fake_stop);
std::set< std::pair< int, stop > > vertex_queue;
vertex_queue.insert(std::make_pair(min_distance[src.id_stop], src));
while (!vertex_queue.empty())
{
int dist = vertex_queue.begin()->first;
stop u = vertex_queue.begin()->second;
vertex_queue.erase(vertex_queue.begin());
// Visit each edge exiting u
const std::vector<neighbor> &neighbors = adj_list[u.id_stop];
for(std::vector<neighbor>::const_iterator neighbor_iter = neighbors.begin();
neighbor_iter != neighbors.end();
neighbor_iter++)
{
stop v = neighbor_iter->target;
int weight = neighbor_iter->weight;
int distance_through_u = dist + weight;
if (distance_through_u < min_distance[v.id_stop]) {
vertex_queue.erase(std::make_pair(min_distance[v.id_stop], v));
min_distance[v.id_stop] = distance_through_u;
previous[v.id_stop] = u;
vertex_queue.insert(std::make_pair(min_distance[v.id_stop], v));
}
}
if(u.id_stop == dst.id_stop)
{
std::cout << "Find : ";
for ( ; dst != fake_stop; dst = previous[dst.id_stop])
{
path.push_front(dst);
}
return path;
}
}
}
int main()
{
std::vector< std::vector<neighbor> > adj_list(9);
stop stop_s;
stop_s.id_stop = 1001;
stop_s.name_stop = "A";
stop stop_x;
stop_x.id_stop = 1002;
stop_x.name_stop = "B";
adj_list[stop_s.id_stop].push_back(neighbor(stop_x, 5));
stop_s.id_stop = 1003;
stop_s.name_stop = "C";
adj_list[stop_x.id_stop].push_back(neighbor(stop_s, 15));
stop_x.id_stop = 1004;
stop_x.name_stop = "D";
adj_list[stop_s.id_stop].push_back(neighbor(stop_x, 20));
stop_s.id_stop = 1001;
stop_s.name_stop = "A";
std::vector<int> min_distance;
std::vector<stop> previous;
std::list<stop> path = dijkstraComputeAndGetShortestPaths(stop_s, stop_x, adj_list, min_distance, previous);
std::cout << "Distance from 1001 to 1004: " << min_distance[stop_x.id_stop] << std::endl;
//std::cout << "Path : ";
#if 0
for (int index = 0; index < path.size(); index++)
{
auto path_front = path.begin();
std::advance(path_front, index);
std::cout << path_front->id_stop << " ";
}
std::cout << std::endl;
#endif
return 0;
}
std::set require you to specify an operator < for the type it holds or you can supply your own comparison functor as a template parameter. Since stop does not have an operator < the operator < from std::pair is not compileable since it relies on using the operator < of the types it holds.. You either need to supply your own comparison functor or define an operator < for stop.

std::sort error using custom classes

I have looked through stackoverflow and added an overload operator to hopefully make it work with sort. Though I still get an explosion of an error saying something is wrong with sort.
Code:
#include <iostream>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <algorithm>
class Student
{
private:
std::string name_;
int number_;
std::vector<int> grades_;
const int num_courses_;
static std::string gen_name() {
return std::to_string(rand());
}
static int gen_number() {
return rand() % (201600000 - 201100000 + 1) + 201100000;
}
static int gen_grade() {
return rand() % (100 - 70 + 1) + 70;
}
double compute_average() {
int marks = 0;
int count = 0;
for (std::vector<int>::iterator i = grades_.begin(); i != grades_.end(); i++, count++){
marks += *i;
}
return static_cast<double>(marks) / count;
}
public:
Student() : name_(gen_name()), number_(gen_number()), num_courses_(5)
{
for (int i = 0; i < num_courses_; ++i) {
grades_.push_back(gen_grade());
}
}
double getAvg() {
return compute_average();
}
friend std::ostream& operator<<(std::ostream& os, Student& s) {
os << "Name = " << s.name_ << "\tNumber = " << s.number_ << "\tAvg = " << s.compute_average();
return os;
}
std::string getName() {
return name_;
}
void print_grades(std::ostream& os) const
{
for (int i = 0; i < num_courses_; ++i) {
os << grades_[i] << ", ";
}
}
bool operator < (const Student& str) const
{
return (name_ < str.name_);
}
};
int main(int argc, char ** argv) {
srand(time(NULL));
if (argc == 2){
int numbOfStudents = atoi(argv[1]);
std::vector<Student> studentVec;
for (int i = 0; i < numbOfStudents; i++){
studentVec.push_back(Student());
}
std::sort(studentVec.begin(), studentVec.end());
for (std::vector<Student>::iterator xi = studentVec.begin(); xi != studentVec.end(); xi++) {
std::cout << *xi << std::endl;
}
}
else{
std::cout << "Usage: " << argv[0] << " {numb} " << std::endl;
}
return 0
}
The error comes when I run sort (I know it's sort since if I comment it out, it works properly). With the error code
In file included from /usr/include/c++/4.9/algorithm:62:0,
from main.cpp:5:
/usr/include/c++/4.9/bits/stl_algo.h: In instantiation of ‘void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >; _Compare = __gnu_cxx::__ops::_Iter_less_iter]’:
/usr/include/c++/4.9/bits/stl_algo.h:1884:70: required from ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >; _Compare = __gnu_cxx::__ops::_Iter_less_iter]’
/usr/include/c++/4.9/bits/stl_algo.h:1970:55: required from ‘void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >; _Compare = __gnu_cxx::__ops::_Iter_less_iter]’
/usr/include/c++/4.9/bits/stl_algo.h:4685:72: required from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >]’
main.cpp:79:50: required from here
/usr/include/c++/4.9/bits/stl_algo.h:1851:17: error: use of deleted function ‘Student& Student::operator=(Student&&)’
*__first = _GLIBCXX_MOVE(__val);
I searched earlier which helped me get to the result of adding a '<' overload, though I still get an error. Can anyone help point out where the mistake is? Thank you. (I compile using g++ --std=c++11)
the member variable const int num_courses_; is const, which means it must be set in the initializer list of the constructor.
num_courses_ can't be set by the copy assignment operator Student& Student::operator=(Student&&), so it prevent the compiler from generating the copy assignment operator for that class. Since there's no copy assignment operator available, and the std::sort function needs it to work, the compilation fails and complains about the copy assignment operator not being available.
Simply remove the const and declare the variable as int num_courses_ and your code should work.

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;
}