I have a problem with threading and passing multiple objects of the same class to the function. It is an external function, inside which I want to call a class method over each of the passed objects.
I have tried passing a vector of objects, as well as a vector of pointers. I have also tried passing them by a reference.
Te specify, I have a "Gas" class, of which 3 objects are constructed in the code earlier. I call a lot of methods in threads before, so I guess that there is no issue with the class.
The compiler returns very long error, the one with _M_invoke(_Index_tuple<_Indices...>):
.In file included from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/thread:39:0,
from ./src/../input.h:22,
from ./src/mass_source.cpp:12:
C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/functional: In instantiation of 'struct std::_Bind_simple<void (*(int, std::reference_wrapper<std::vector<Ref::Gas> >))(int, std::vector<Ref::Gas>&)>':
C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/thread:142:59: required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, std::vector<Ref::Gas>&); _Args = {int&, std::reference_wrapper<std::vector<Ref::Gas, std::allocator<Ref::Gas> > >}]'
./src/mass_source.cpp:86:50: required from here
C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/functional:1505:61: error: no type named 'type' in 'class std::result_of<void (*(int, std::reference_wrapper<std::vector<Ref::Gas> >))(int, std::vector<Ref::Gas>&)>'
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/functional:1526:9: error: no type named 'type' in 'class std::result_of<void (*(int, std::reference_wrapper<std::vector<Ref::Gas> >))(int, std::vector<Ref::Gas>&)>'
_M_invoke(_Index_tuple<_Indices...>)
The error message comes from my "original" code, in which I have commented out all of the lines, which are not presented below. As it was reported to be confusing, here is an explanation:
from ./src/../input.h:22 - inclusion of thread library
from ./src/mass_source.cpp:12: - inclusion of the above input.h file
./src/mass_source.cpp:86: - calc_ms fucntion call
Below the class declaration is attached:
namespace Ref{
class Gas{
public:
Gas(const int id, const int& imax, const int& jmax){
id_ = id;
NX_ = imax;
NR_ = jmax;
}
void set_ms(int m, double& mass_source){
ms_[m] = mass_source;
}
private:
int id_;
int NX_, NR_;
std::vector<double> ms_;
};
} //end of namespace
Code calling the function I have trouble with (creation of Gas objects and their pointers included):
using namespace Ref;
void calc_ms(int m, std::vector<Gas>& GAS);
int main(){
int i;
std::vector<Gas> gases;
std::vector<Gas*> ptr_gas(3);
for(i = 0; i < 3; i++){
gases.push_back(Gas(i, grid));
}
for(i = 0; i < 3; i++){
ptr_gas[i] = &gases[i];
}
std::vector<std::thread*> th_gas;
for(i = 0; i < 20; i++){
std::thread *thr = new std::thread(calc_ms, i, std::ref(gases));
th_gas.push_back(thr);
}
for(auto &X : th_gas){
X->join();
delete X;
}
th_gas.clear();
}
And the calc_ms fucntion definition:
using namespace Ref;
void calc_ms(int m, std::vector<Gas>& GAS){
double MassSourceCH4 = .... ;
double MassSourceCO = .... ;
double MassSourceCO2 = .... ;
GAS[0].set_ms(m, MassSourceCH4);
GAS[1].set_ms(m, MassSourceCO);
GAS[2].set_ms(m, MassSourceCO2);
}
I have also tried passing gases by copy, and ptr_gas as a reference and copy.
COMMENT: The ms_ member of Gas class is resized somwhere else in the code, thus the assignment with using indexes is not a problem.
Here is a simplified version showing how to use threads correctly and how to pass a vector to a thread by reference:
class Gas { /*...*/ };
void calc_ms(int m, std::vector<Gas>& gases);
int main() {
std::vector<Gas> gases;
std::vector<std::thread> th_gas;
for(int i = 0; i < 20; ++i)
th_gas.emplace_back(calc_ms, i, std::ref(gases));
for(auto& t : th_gas)
t.join();
th_gas.clear();
}
Related
I have a Container class that is meant to store a vector of shared pointers. Whenever an item is appended to the Container, I want it to assume ownership of that item. In other words, when the Container is deconstructed, all of the elements inside it should also be deconstructed.
template <typename T>
class Container
{
private:
const std::vector<std::shared_ptr<T>> vec_;
public:
void append(std::shared_ptr<T> item)
{
vec_.push_back(std::move(item));
}
void printElements()
{
for (int i = 0; i < vec_.size(); i++) { std::cout << vec_[i] << std::endl; }
}
};
int main(int argc, char** argv) {
std::unique_ptr<Container<std::string>> c = std::make_unique<Container<std::string>>();
c->append(std::make_shared<std::string>("hello"));
return 0;
}
The problem is, I get the following error on vec_.push_back(std::move(item)).
No matching member function for call to 'push_back'
I'm not sure why this error is occurring.
Original answer:
Your std::vector, vec_ is const. Seems to me that would forcefully remove or disable any method, such as push_back(), which tries to modify the const vector.
Additions added 10 May 2020:
I think it's worth expounding upon this comment from #Carpetfizz in the comments under his question, too:
#GabrielStaples thanks, removing const did the trick. I thought const only protected against reassignment of vector_ but allowed for it to be mutated?
My response:
No, const here applies to the contents of the vector. The vector isn't a pointer, but what you're talking about could be done with pointers, by making the pointer itself const instead of the contents of what it points to const. Also, const and mutable are opposites. One undoes the other. You cannot have both in effect at the same time. By definition, something constant is immutable (unchangeable), and something mutable is non-constant.
And how might one make a pointer const but not the contents of what it points to?
First, consider the original code (with some minor modifications/fixes I did to it):
Run it yourself online here: https://onlinegdb.com/SyMqoeU9L
1) cpp_template_const_vector_of_smart_ptrs_test_BEFORE.cpp:
#include <iostream>
#include <memory>
#include <vector>
template <typename T>
class Container
{
private:
// const std::vector<std::shared_ptr<T>> vec_; // does NOT work
std::vector<std::shared_ptr<T>> vec_; // works!
public:
void append(std::shared_ptr<T> item)
{
vec_.push_back(std::move(item));
}
void printElements()
{
for (int i = 0; i < vec_.size(); i++)
{
// Don't forget to dereference the pointer with `*` in order to
// obtain the _contens of the pointer_ (ie: what it points to),
// rather than the pointer (address) itself
std::cout << *vec_[i] << std::endl;
}
}
};
int main(int argc, char** argv)
{
std::unique_ptr<Container<std::string>> c = std::make_unique<Container<std::string>>();
c->append(std::make_shared<std::string>("hello"));
c->append(std::make_shared<std::string>("world"));
c->printElements();
return 0;
}
Output:
hello
world
And here's the new code demonstrating how to make a constant pointer to a non-const vector. See my comments here, and study the changes:
Run it yourself online here: https://onlinegdb.com/HyjNx-L5U
2) cpp_template_const_vector_of_smart_ptrs_test_AFTER.cpp
#include <iostream>
#include <memory>
#include <vector>
template <typename T>
class Container
{
private:
// const std::vector<std::shared_ptr<T>> vec_; // does NOT work
// Create an alias to this type just to make the creation below less
// redundant in typing out the long type
using vec_type = std::vector<std::shared_ptr<T>>;
// NON-const object (vector)--so it can be changed
vec_type vec_;
// const pointer to NON-const object--so, vec_p_ can NOT be re-assigned to
// point to a new vector, because it is `const`! But, **what it points to**
// CAN be changed because it is NOT const!
vec_type * const vec_p_ = &vec_;
// This also does NOT work (in place of the line above) because it makes
// the **contents of what you're pointing to const**, which means again
// that the contents of the vector can NOT be modified.
// const vec_type * const vec_p_ = &vec_; // does NOT work
// Here's the compile-time error in gcc when compiling for C++17:
// main.cpp: In instantiation of ‘void Container<T>::append(std::shared_ptr<_Tp>) [with T = std::basic_string<char>]’:
// <span class="error_line" onclick="ide.gotoLine('main.cpp',78)">main.cpp:78:53</span>: required from here
// main.cpp:61:9: error: passing ‘const vec_type {aka const std::vector >, std::allocator > > >}’ as ‘this’ argument discards qualifiers [-fpermissive]
// vec_p_->push_back(std::move(item));
// ^~~~~~
// In file included from /usr/include/c++/7/vector:64:0,
// from main.cpp:22:
// /usr/include/c++/7/bits/stl_vector.h:953:7: note: in call to ‘void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = std::shared_ptr >; _Alloc = std::allocator > >; std::vector<_Tp, _Alloc>::value_type = std::shared_ptr >]’
// push_back(value_type&& __x)
// ^~~~~~~~~
// To prove that vec_p_ can NOT be re-assigned to point to a new vector,
// watch this:
vec_type vec2_;
// vec_p_ = &vec2_; // COMPILE-TIME ERROR! Here is the error:
// main.cpp:44:5: error: ‘vec_p_’ does not name a type; did you mean ‘vec_type’?
// vec_p_ = &vec2_; // COMPILE-TIME ERROR!
// ^~~~~~
// vec_type
// BUT, this works just fine:
vec_type * vec_p2_ = &vec2_; // non-const pointer to non-const data
public:
void append(std::shared_ptr<T> item)
{
vec_p_->push_back(std::move(item));
}
void printElements()
{
for (int i = 0; i < vec_p_->size(); i++)
{
// Notice we have to use a double de-reference here now!
std::cout << *(*vec_p_)[i] << std::endl;
}
}
};
int main(int argc, char** argv)
{
std::unique_ptr<Container<std::string>> c = std::make_unique<Container<std::string>>();
c->append(std::make_shared<std::string>("hello"));
c->append(std::make_shared<std::string>("world"));
c->printElements();
return 0;
}
Output:
hello
world
I am trying to implement an API layer for a C++ project, here's a small example of what I want to achieve:
double data[8] = {0,1,2,3,4,5,6,7};
template<typename T>
void cpy(T *buf){
for(int i=0; i<8; i++)
buf[i] = (T)data[i];
}
int main() {
int a[8];
cpy(a);
float b[8];
cpy(b);
double c[2][4];
cpy(c); //error: functional cast to array type 'double [4]'
return 0;
}
The idea is to allow the user to use the function cpy() for different types of array without having to do cpy<double>(c) or cpy((double *)c) but in this example, calling cpy() with a 2D array leads to compilation error:
error: expected initializer before 'cpy'
In instantiation of 'void cpy(T*) [with T = double [4]]':
required from here
error: functional cast to array type 'double [4]'
How can we achieve this?
Assuming you cannot change main() (except for typo with missing ;).
You can add overload:
template<typename T>
void cpy(T *buf){
for (int i = 0; i != 8; ++i) {
buf[i] = data[i];
}
}
template<typename T, std::size_t N>
void cpy(T (*buf)[N]){
cpy(&buf[0][0]);
}
Demo
I basically have an std::deque of objects, and I want to remove some of these objets according a condition on a given member variable of the objects, so that I use a predicate, but I have errors that I don't really understand.
I am using g++ with the -std=c++11 for STL reasons (shared pointers) but I was trying to work this out on windows with MVS with non c++11 code, so that I am looking for a non c++11 solution, without lamdas etc
The code is :
#include <iostream> // for std::cout and std::endl
#include <cstdio> // for getchar()
#include <memory> // for std::shared_ptr
#include <deque> // for std::deque
#include <algorithm> // for std::earse and std::remove_if
class A
{
private:
int _i;
double _d;
public:
A(int i, double d)
{
_i = i;
_d = d;
}
int geti()const
{
return _i;
}
double getValueOnWhichToCheck()const
{
return _d;
}
};
typedef std::shared_ptr<A> A_shared_ptr;
typedef std::deque<A_shared_ptr> list_type;
void PrintDeque(list_type & dq)
{
if (0 == dq.size())
{
std::cout << "Empty deque." << std::endl;
}
else
{
for (int i = 0 ; i < dq.size() ; ++i)
{
std::cout << i+1 << "\t" << dq[i] << std::endl;
}
}
}
class B
{
public:
double getThreshold() // Non constant for a reason as in real code it isn't
{
return 24.987; // comes from a calculation not needed here so I return a constant.
}
bool Predicate(A_shared_ptr & a)
{
return a->getValueOnWhichToCheck() >= getThreshold();
}
void DoStuff()
{
A_shared_ptr pT1 = std::make_shared<A>(A(2, -6.899987));
A_shared_ptr pT2 = std::make_shared<A>(A(876, 889.878762));
A_shared_ptr pT3 = std::make_shared<A>(A(-24, 48.98924));
A_shared_ptr pT4 = std::make_shared<A>(A(78, -6654.98980));
A_shared_ptr pT5 = std::make_shared<A>(A(6752, 3.141594209));
list_type dq = {pT1,pT2,pT3,pT4,pT5};
PrintDeque(dq);
bool (B::*PtrToPredicate)(A_shared_ptr &) = &B::Predicate;
dq.erase(std::remove_if(dq.begin(), dq.end(), PtrToPredicate),dq.end());
PrintDeque(dq);
}
};
int main()
{
B * pB = new B();
pB->DoStuff();
getchar();
}
and the output of g++ -std=c++11 main.cpp -o main is :
In file included from /usr/include/c++/5/bits/stl_algobase.h:71:0,
from /usr/include/c++/5/bits/char_traits.h:39,
from /usr/include/c++/5/ios:40,
from /usr/include/c++/5/ostream:38,
from /usr/include/c++/5/iostream:39,
from main.cpp:1:
/usr/include/c++/5/bits/predefined_ops.h: In instantiation of ‘bool __gnu_cxx::__ops::_Iter_pred<_Predicate>::operator()(_Iterator) [with _Iterator = std::_Deque_iterator<std::shared_ptr<A>, std::shared_ptr<A>&, std::shared_ptr<A>*>; _Predicate = bool (B::*)(std::shared_ptr<A>&)]’:
/usr/include/c++/5/bits/stl_algo.h:866:20: required from ‘_ForwardIterator std::__remove_if(_ForwardIterator, _ForwardIterator, _Predicate) [with _ForwardIterator = std::_Deque_iterator<std::shared_ptr<A>, std::shared_ptr<A>&, std::shared_ptr<A>*>; _Predicate = __gnu_cxx::__ops::_Iter_pred<bool (B::*)(std::shared_ptr<A>&)>]’
/usr/include/c++/5/bits/stl_algo.h:936:30: required from ‘_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = std::_Deque_iterator<std::shared_ptr<A>, std::shared_ptr<A>&, std::shared_ptr<A>*>; _Predicate = bool (B::*)(std::shared_ptr<A>&)]’
main.cpp:67:73: required from here
/usr/include/c++/5/bits/predefined_ops.h:234:30: error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘((__gnu_cxx::__ops::_Iter_pred<bool (B::*)(std::shared_ptr<A>&)>*)this)->__gnu_cxx::__ops::_Iter_pred<bool (B::*)(std::shared_ptr<A>&)>::_M_pred (...)’, e.g. ‘(... ->* ((__gnu_cxx::__ops::_Iter_pred<bool (B::*)(std::shared_ptr<A>&)>*)this)->__gnu_cxx::__ops::_Iter_pred<bool (B::*)(std::shared_ptr<A>&)>::_M_pred) (...)’
{ return bool(_M_pred(*__it)); }
^
Not a fan of function pointers, but using lambda's this seems to compile... https://ideone.com/0StRcw
dq.erase(std::remove_if(dq.begin(), dq.end(), [this](const std::shared_ptr<A>& a) {
return a->getValueOnWhichToCheck() >= getThreshold();
}),dq.end());
Or without lambdas..
auto predicateToUse = std::bind(&B::Predicate, this, std::placeholders::_1);
dq.erase(std::remove_if(dq.begin(), dq.end(), predicateToUse), dq.end());
Update no auto:
dq.erase(std::remove_if(dq.begin(), dq.end(), std::bind(&B::Predicate, this, std::placeholders::_1)), dq.end());
You are not going to be able to use a non static member function pointer with remove_if. remove_if requires a normal function pointer, static member function pointer or a function object. The reason it cannot use a member function pointer is because it needs an instance of the class in order to be able to call the function and you cannot wrap that into the call
You are either need to make Predicate static, create a function object and pass an instance of that, or use a lambda in the call site.
I am getting an error and it happens right at line Chest_vect.push_back(newChest); From my knowledge I don't see anything wrong with it. But I am sure I probably missed something small. If you can help that would be appreciated! Thanks either way!
class Chest_objects {
private:
int loc_x, loc_y;
int map_x, map_y;
string obj_name = "";
string obj_id = "";
bool obj_trigger = false;
bool obj_visible = false;
public:
void setLoc_x(int x)
{
loc_x = x;
}
void setLoc_y(int y)
{
loc_y = y;
}
//OTHER GETTER AND SETTER FUNCTIONS NOT INCLUDED
Chest_objects(int x, int y); //CONSTRUCTOR FUNCTIONS: NOTE I DON'T HAVE A COMPLETE ONE
Chest_objects();
Chest_objects(int x, int y, int my, int mx, string name, string id, bool trig, bool vis);
int getChestVect(vector<Chest_objects>& Chest_vect, const char*getFile)
{
int amount = 0;
int get_x = 0;
int get_y = 0;
int max_x;
int max_y;
char get_info;
ifstream file;
file.open(getFile);
file >> max_x >> max_y;
while(get_info != '0')
{
file >> get_info;
if(get_info == '.')
{
get_x++;
}
if(get_info == 'B')
{
Chest_objects newChest(get_x, get_y);
Chest_vect.push_back(newChest);
get_x++;
amount++;
}
if(get_x >= max_x)
{
get_x = 0;
get_y++;
}
}
return amount;
}
};
int main()
{
... blah
return 0;
}
Chest_objects::Chest_objects(int x, int y)
{
loc_x = x;
loc_y = y;
}
Chest_objects::Chest_objects()
{
loc_x = 0;
loc_y = 0;
}
error: In instantiation of 'void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vector<_Tp, _Alloc>::iterator, const _Tp&) [with _Tp = Chest_objects; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator >; typename std::_Vector_base<_Tp, _Alloc>::pointer = Chest_objects*]':|
error: 'std::ios_base::ios_base(const std::ios_base&)' is private|
The push_back method requires that the type contained in the container be copyable. The error implies that the Chest_objects class has only a private constructor. So check that Chest_objects has:
A copy constructor: Chest_objects(const Chest_objects&);
A copy operator: Chest_objects& operator=(const Chest_objects& rhs);
and that they are both public.
Another possibility is that you subclasses Chest_objects from one of the classes in <iostream>, which is not recommended, and the compiler's seeing a constructor that takes std::ios marked private, which means you can't instantiate or subclass it. This can happen with singletons.
But there's no way to be sure since you didn't post all the code. Also, before posting code, try to cut out as much code as possible while preserving the error.
There's your problem:
ifstream small_obj_map;
You're instantiating an ifstream inside the object. Every object in the Chest_vect will have its own ifstream. This is almost certainly not what you want.
Since you have not written copy constructors or copy operators, the compiler is trying to create them for you. And the default copy constructor will try to construct small_obj_map from the small_obj_map of the object being copied. But ifstream has no copy constructor because it's not meant to be copied.
You should instead create the ifstream only when you need it, inside the method that needs it, and let it be destroyed when the method exits. It should not be a part of the object because it has no need to persist with the object.
In the following code, i am getting error:
city.cc: In member function ‘std::vector<std::basic_string<char> > MyCity::get_neighbours()’:
city.cc:25:42: error: base operand of ‘->’ has non-pointer type ‘std::pair<MyCity*, double>’
In file included from /depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_algobase.h:65:0,
from /depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/char_traits.h:41,
from /depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/ios:41,
from /depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/ostream:40,
from /depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/iostream:40,
from city.cc:1:
/depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_pair.h: In instantiation of ‘std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = std::basic_string<char>; _U2 = double; _T1 = MyCity*; _T2 = double]’:
city.cc:18:50: required from here
/depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_pair.h:111:39: error: cannot convert ‘const std::basic_string<char>’ to ‘MyCity*’ in initialization
.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class MyCity {
string name;
std::vector<pair<MyCity*,double> > neighbours;
public:
MyCity()
{
// neighbours.clear();
}
MyCity(string s, string s1, double d)
{
name = s;
neighbours.push_back(std::make_pair(s1,d));
}
std::vector<string> get_neighbours( )
{
std::vector<string> names;
for (size_t i = 0; i< neighbours.size(); ++i)
{
names.push_back(neighbours[i]->first->get_name());
}
return names;
}
};
class MyState {
vector<MyCity*> cities;
string name;
public:
MyState() { }
MyState(string s) {
name =s;
}
bool add_city(string name, string neigh, double d)
{
MyCity* c = new MyCity(name,neigh,d);
cities.push_back(c);
return true;
}
};
Do not dereference the std::pair as it is not a pointer.
std::vector<string> get_neighbours( )
{
std::vector<string> names;
for (size_t i = 0; i< neighbours.size(); ++i)
names.push_back(neighbours[i].first->get_name());
return names;
}
You also have a problem in your constructor, the std::make_pair(s1, d) will return a std::pair<std::string, double> so it cannot be pushed back to you neighbours vector.
Try something like that:
MyCtiy(string s)
:name(s)
{
}
MyCity(string s, string s1, double d)
:name(s)
{
created_neighbours.emplace_back(new neighbour(s1));
MyCity* city = created_neighbours.back().get();
neighbours.push_back(std::make_pair(city, d));
city->addNeighbour(this, d);
}
private:
std::vector<std::unique_ptr<MyCity>> created_neighbours;
void addNeighbour(MyCity* city, double d)
{
neighbours.push_back(std::make_pair(city, d));
}
Note: you can strip the addNeighbourd part if you don't want the association to be many-to-many.
Edit: Fix the addNeighbour to give a MyCity pointer. Created a created_neighbours collection to store (and free) created neighbours.
3 mistakes can be found in your code. Please find and correct the following 2 lines in your code
neighbours.push_back(std::make_pair(some_pointer_to_the_MyCity_object,d));
names.push_back(neighbours[i].first->get_name());
And you have to implement the get_name() function in MyCity class
Now it should be compiled