I have a class with some huge objects that I need to access in a const fashion. To do that I have the getABC() member function that copies these objects to the outside world. Is it possible to directly access them, since the copy operations are very slow in my case? shared_ptr would be preferable, and also I want to avoid making tuples just to return them in the getABC()
#include <iostream>
#include <vector>
using namespace std;
class foo {
private:
int a;
vector<int> b; // HUGE OBJECT
vector<int> c; // HUGE OBJECT
public:
foo(int a_, vector<int> b_, vector<int> c_) : a(a_), b(b_), c(c_) { }
void printfoo() {
cout << "a = " << a << endl;
cout << "b = ";
for(auto v:b) {
cout << v << " ";
}
cout << endl;
cout << "c = ";
for(auto v:c) {
cout << v << " ";
}
cout << endl;
}
void getABC(int & a_in, vector<int> & b_in, vector<int> & c_in ) const {
a_in = a;
b_in = b; // SLOW
c_in = c; // SLOW
}
};
int main() {
int in = 4;
vector<int> inA {1, 2, 3, 5};
vector<int> inB {2, 2, 3, 5};
foo bar(in, inA, inB);
bar.printfoo();
// GET THE MEMBERS
int out = 0;
vector<int> outA;
vector<int> outB;
bar.getABC(out, outA, outB);
// PRINT
cout << "OUT = " << out;
cout << "\nOUTA = ";
for(auto const &v : outA ) {
cout << v << " ";
}
cout << endl;
cout << "OUTB = ";
for(auto const &v : outA ) {
cout << v << " ";
}
cout << endl;
return 0;
}
I want to avoid making tuples just to return them in the getABC()
Why? It seems the most straightforward way to return references to multiple pieces of data:
tuple<const int&, const vector<int>&, const vector<int>&> getABC() const
{ return std::make_tuple(std::cref(a), std::cref(b), std::cref(c)); }
auto refs = bar.getABC();
for (auto& x : std::get<1>(refs))
// ...
Or create a named struct to return instead:
struct DataRefs {
int a;
const std::vector<int>& b;
const std::vector<int>& c;
};
DataRefs getABC() const { return { a, b, c }; }
This has the advantage that you don't need to use std::get<N> to access the members, and can just use sensible names:
auto refs = bar.getABC();
for (auto& x : refs.b)
// ...
From your comment maybe you want something like this, but this would be a dumb interface:
void getABC(const int*& pa, const std::vector<int>*& pb, const std::vector<int>*& pc) const
{
pa = &a;
pb = &b;
pc = &c;
}
Which you could use like this:
int* a;
std::vector<int>* b;
std::vector<int>* c;
bar.getABC(a, b, c);
for (auto& x : *b)
// ...
As you can see, this is more verbose for the caller, and is just ugly and not idiomatic C++.
Or you could move the data into a separate sub-object:
class foo
{
struct data
{
int a;
std::vector<int> b;
std::vector<int> c;
};
data m_data;
public:
const data& getData() const { return m_data; };
};
auto& refs = bar.getData();
for (auto& x : refs.b)
// ...
You could have 3 separate functions that return const references (not necessary for the int):
class foo {
...
int getA() const { return a; }
const vector<int>& getB() const { return b; }
const vector<int>& getC() const { return c; }
};
These can even be inlined by the compiler so you don't need to actually put them anywhere. Just call bar.getB() whenever you need to use b. Even without inlining you're most likely not going to notice a performance hit.
Related
please i m trying to write a function that accept a vector of smart pointer or regular pointer but it never work, I want to write function getLargestRadius()
that accept as argument std::vector<something*>
or std::vector<std::shared_ptr<something>>.
the only way it work for me is by overloading the function
here is my full code to understand exactly what i mean:
#include <iostream>
#include <vector>
#include <memory>
class Point
{
private:
int m_x{ 0 };
int m_y{ 0 };
int m_z{ 0 };
public:
Point() = default;
Point(int x, int y, int z)
: m_x{x}, m_y{y}, m_z{z}
{
}
friend std::ostream& operator<<(std::ostream &out, const Point &p)
{
out << "Point(" << p.m_x << ", " << p.m_y << ", " << p.m_z << ')';
return out;
}
};
class Shape
{
public:
virtual std::ostream& print(std::ostream &out) const = 0;
friend std::ostream& operator <<(std::ostream &out, const Shape &shape)
{
return shape.print(out);
}
virtual ~Shape() {}
};
class Triangle : public Shape
{
private:
Point m_a;
Point m_b;
Point m_c;
public:
Triangle(const Point &a, const Point &b, const Point &c)
: m_a{a}, m_b{b}, m_c{c}
{}
virtual std::ostream& print(std::ostream &out) const override
{
out << "Trinagle(";
out << m_a << ", ";
out << m_b << ", ";
out << m_c << ")";
return out;
}
};
class Circle: public Shape
{
private:
Point m_center;
int m_radius;
public:
Circle(const Point ¢er, int radius)
: m_center{center}, m_radius{radius}
{
}
virtual std::ostream& print(std::ostream &out) const override
{
out << "Circle(" << m_center << ", radius " << m_radius << ')';
return out;
}
int getRadius() const {return m_radius;}
};
int getLargestRadius(std::vector<std::shared_ptr<Shape>> &v)
{
int largestRadius { 0 };
for(int x{0}; x < static_cast<int>(v.size()); ++x)
{
if (dynamic_pointer_cast<Circle>(v[x]))
{
if (dynamic_cast<Circle&>(*v[x]).getRadius() > largestRadius)
largestRadius = dynamic_cast<Circle&>(*v[x]).getRadius();
}
}
return largestRadius;
}
int getLargestRadius(std::vector<Shape*> &v)
{
int largestRadius { 0 };
for(int x{0}; x < static_cast<int>(v.size()); ++x)
{
if (dynamic_cast<Circle*>(v[x]))
{
if (dynamic_cast<Circle*>(v[x])->getRadius() > largestRadius)
largestRadius = dynamic_cast<Circle*>(v[x])->getRadius();
}
}
return largestRadius;
}
int main()
{
std::vector<std::shared_ptr<Shape>> v1 {
std::make_shared<Circle>(Point{1, 2, 3}, 7),
std::make_shared<Triangle>(Point{1, 2, 3}, Point{4, 5, 6}, Point{7, 8, 9}),
std::make_shared<Circle>(Point{4, 5, 6}, 3)
};
std::vector<Shape*> v2{
new Circle{Point{1, 2, 3}, 7},
new Triangle{Point{1, 2, 3}, Point{4, 5, 6}, Point{7, 8, 9}},
new Circle{Point{4, 5, 6}, 3}
};
for(auto &element : v1)
std::cout << *element << '\n';
std::cout << "The largest radius is: " << getLargestRadius(v1) << '\n';
std::cout << "The largest radius is: " << getLargestRadius(v2) << '\n';
for(auto &element : v2)
delete element;
return 0;
}
i tried to make it as template but nothing work.
as you can see i had to overload the function to let it work with both vector type
so is there a way to use template to make it only one function work with all type.
thank you
Without check, you might do, with template:
template <typename T>
int getLargestRadius(const std::vector<T>& v)
{
int largestRadius { 0 };
for (const auto& shapePtr : v)
{
if (const auto* circle = dynamic_cast<const Circle*>(&*shapePtr))
{
largestRadius = std::max(largestRadius , circle->radius);
}
}
return largestRadius;
}
To treat both regular and smart pointer equally, I deference them (*shapePtr) so then I have a reference.
(then I need to got back regular pointer, so I take address &*shapePtr).
There are tons of answers for sorting a vector of struct in regards to a member variable. That is easy with std::sort and a predicate function, comparing the structs member. Really easy.
But I have a different question. Assume that I have the following struct:
struct Test {
int a{};
int b{};
int toSort{};
};
and a vector of that struct, like for example:
std::vector<Test> tv{ {1,1,9},{2,2,8},{3,3,7},{4,4,6},{5,5,5} };
I do not want to sort the vectors elements, but only the values in the member variable. So the expected output should be equal to:
std::vector<Test> tvSorted{ {1,1,5},{2,2,6},{3,3,7},{4,4,8},{5,5,9} };
I wanted to have the solution to be somehow a generic solution. Then I came up with a (sorry for that) preprocessor-macro-solution. Please see the following example code:
#include <iostream>
#include <vector>
#include <algorithm>
struct Test {
int a{};
int b{};
int toSort{};
};
#define SortSpecial(vec,Struct,Member) \
do { \
std::vector<decltype(Struct::Member)> vt{}; \
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [](const Struct& s) {return s.Member; }); \
std::sort(vt.begin(), vt.end()); \
std::for_each(vec.begin(), vec.end(), [&vt, i = 0U](Struct & s) mutable {s.Member = vt[i++]; }); \
} while (false)
int main()
{
// Define a vector of struct Test
std::vector<Test> tv{ {1,1,9},{2,2,8},{3,3,7},{4,4,6},{5,5,5} };
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
// Call sort macro
SortSpecial(tv, Test, toSort);
std::cout << "\n\nSorted\n";
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
}
Since macros shouldn't be used in C++, here my questions:
1. Is a solution with the algorithm library possible?
2. Or can this be achieved via templates?
To translate your current solution to a template solution is fairly straight forward.
template <typename T, typename ValueType>
void SpecialSort(std::vector<T>& vec, ValueType T::* mPtr) {
std::vector<ValueType> vt;
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [&](const T& s) {return s.*mPtr; });
std::sort(vt.begin(), vt.end());
std::for_each(vec.begin(), vec.end(), [&, i = 0U](T& s) mutable {s.*mPtr = vt[i++]; });
}
And we can call it by passing in the vector and a pointer-to-member.
SpecialSort(tv, &Test::toSort);
Somewhow like this (You just need to duplicate, rename and edit the "switchToShort" funtion for the rest of the variables if you want):
#include <iostream>
#include <vector>
struct Test {
int a{};
int b{};
int toSort{};
};
void switchToShort(Test &a, Test &b) {
if (a.toSort > b.toSort) {
int temp = a.toSort;
a.toSort = b.toSort;
b.toSort = temp;
}
}
//void switchToA(Test& a, Test& b) { ... }
//void switchToB(Test& a, Test& b) { ... }
inline void sortMemeberValues(std::vector<Test>& data, void (*funct)(Test&, Test&)) {
for (int i = 0; i < data.size(); i++) {
for (int j = i + 1; j < data.size(); j++) {
(*funct)(data[i], data[j]);
}
}
}
int main() {
std::vector<Test> tv { { 1, 1, 9 }, { 2, 2, 8 }, { 3,3 ,7 }, { 4, 4, 6 }, { 5, 5, 5} };
sortMemeberValues(tv, switchToShort);
//sortMemeberValues(tv, switchToA);
//sortMemeberValues(tv, switchToB);
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
}
With range-v3 (and soon ranges in C++20), you might simply do:
auto r = tv | ranges::view::transform(&Test::toSort);
std::sort(r.begin(), r.end());
Demo
I'm trying to use enum types to indexig some array but I want to allow different ordering of the vector depending on some option. In the class I also want functions that take the enum variable as input and use it as it should.
The solution I found is the following
#include<iostream>
#include<array>
#include<vector>
struct A{
struct XYZ{
enum coord{X=0,Y,Z};
};
struct YZX{
enum coord{Y=0,Z,X};
};
struct ZXY{
enum coord{Z=0,X,Y};
};
std::array<std::vector<float>,3> val;
void resize(int opt, size_t dim){
val[opt].resize(dim);
return;
}
void printsize(){
for(auto & i : val){
std::cout << i.size() << " ";
}
std::cout << std::endl;
return;
}
};
int main(){
A foo1;
A foo2;
A foo3;
foo1.resize(XYZ::X,10);
foo2.resize(YZX::X,10);
foo3.resize(ZXY::X,10);
std::cout << "Size foo1\n";
foo1.printsize();
std::cout << "Size foo2\n";
foo2.printsize();
std::cout << "Size foo3\n";
foo3.printsize();
return 0;
}
What I don't like in this solution is that my function resize takes an integer type as input and there's no type control of the enum.
Is there any other smarter solution? Am I doing something considered as anti-pattern?
Thank you
I suggest you to modify the member function resize (three parameters instead of two) and exploit the type safety of the enum classes:
#include <stdio.h>
#include<iostream>
#include<array>
#include<vector>
struct A{
enum class Coordinate
{
X = 0,
Y = 1,
Z = 2
};
enum class Permutation
{
XYZ = 0,
ZXY = 1,
YZX = 2
};
std::array<std::vector<float>,3> val;
/* resize takes three parameters now */
void resize(Permutation p, Coordinate c, size_t dim)
{
int index = ( static_cast<int>(p) + static_cast<int>(c) ) % 3 ;
val[index].resize(dim);
return;
}
void printsize(){
for(auto & i : val){
std::cout << i.size() << " ";
}
std::cout << std::endl;
return;
}
};
int main()
{
A foo1;
A foo2;
A foo3;
foo1.resize(A::Permutation::XYZ, A::Coordinate::X,10);
foo2.resize(A::Permutation::YZX, A::Coordinate::X,10);
foo3.resize(A::Permutation::ZXY, A::Coordinate::X,10);
std::cout << "Size foo1\n";
foo1.printsize();
std::cout << "Size foo2\n";
foo2.printsize();
std::cout << "Size foo3\n";
foo3.printsize();
return 0;
}
How about an Index class, constructible from several enum classes?
struct A
{
enum class XYZ {X,Y,Z};
enum class YZX {Y,Z,X};
enum class ZXY {Z,X,Y};
struct Index
{
int value;
operator int() const {return value;}
Index(XYZ value) : value(int(value)) {}
Index(YZX value) : value(int(value)) {}
Index(ZXY value) : value(int(value)) {}
};
std::array<std::vector<float>, 3> val;
void resize(Index opt, size_t dim)
{
val[opt].resize(dim);
}
void printsize() const
{
for (const auto &i : val)
std::cout << i.size() << ' ';
std::cout << '\n';
}
};
I'm trying to display a vector contents named l_anMarking, but I'm getting this error message:
error : expression must have class type while trying to match the argument list '(std::ostream, std::vector<long,std::allocator<_Ty>>)
I don't understand why I'm having this error. This is my code:
Header file:
class SPSIM_EXPORT ParaStochSimulator : public StochasticSimulator
{
private:
protected:
VectorLong m_anCurrentMarking;
long m_nMinTransPos;
public:
void first_reacsimulator();
void ParaStochSimulator::broad_cast(long);
}
cpp:
void ParaStochSimulator::first_reacsimulator()
{
if (mnprocess_id==0)
{
broad_cast(m_anCurrentMarking);
}
}
void ParaStochSimulator::broad_cast(long j)
{
std::cout << "i'm broad_casting" << std::endl;
double val;
//Get manipulated places
VectorLong l_nMinplacesPos = (*m_pcTransitionsInfo)[j]->GetManipulatedPlaces();
double* l_anMarking=new double [l_nMinplacesPos.size()];
//l_anMarking.clear();
//double var = l_nMinplacesPos.size();
int i = 0;
for (auto lnpos : l_nMinplacesPos)
{
val = m_anCurrentMarking[lnpos];
l_anMarking[i++] = val;
}
std::vector<VectorLong>::iterator it;
for (it = l_anMarking.begin(); it < l_anMarking.end(); it++) //here
{
std::cout << *it << std::endl;
}
MPI_Bcast(&l_anMarking, sizeof l_nMinplacesPos, MPI_DOUBLE, 0, MPI_COMM_WORLD);
delete[] l_anMarking;
}
int main()
{
((spsim::ParaStochSimulator*)l_pcStochSolver)->first_reacsimulator();
}
Your l_anMarking variable is declared as a raw double* pointer, but you are trying to treat it as an STL container by calling begin() and end() on it. Thus the compiler error.
You have two choices:
Change the second for loop to use indexes instead of iterators.
for (int k = 0; k < i; ++k)
{
std::cout << l_anMarking[k] << std::endl;
}
Change l_anMarking to be a std::vector<double> instead (and adjust MPI_Bcast()) accordingly):
std::vector<double> l_anMarking;
l_anMarking.reserve(l_nMinplacesPos.size());
for (auto lnpos : l_nMinplacesPos)
{
val = m_anCurrentMarking[lnpos];
l_anMarking.push_back(val);
}
for (auto marking : l_anMarking)
{
std::cout << marking << std::endl;
}
The compiler error is referring to not being able to print the VectorLong to std::cout
std::vector<VectorLong>::iterator it;
for (it = l_anMarking.begin(); it < l_anMarking.end(); it++) //here
{
std::cout << *it << std::endl; // need an operator<< for your VectorLong
}
You should add something like this:
std::ostream & operator<<(std::ostream &os, const VectorLong& v)
{
os << "VectorLong: ";
for (const auto &l : v)
os << l << " ";
return os;
}
I'm not getting the syntax right. Lets say I have this...
#include <set>
...
struct foo{
int bar;
string test;
};
struct comp{
inline bool operator()(const foo& left,const foo& right){
return left.bar < right.bar;
}
};
int main(){
std::multiset<foo,comp> fooset;
std::multiset<foo,comp>::iterator it;
...//insert into fooset
for (it = fooset.begin(); it != fooset.end(); it++){
//how do i access int bar and string test of each element?
}
return 0;
}
How do i access int bar and string test of each element inside the for loop?
Thanks!
There is a good mnemonic rule that an iterator is a safe C++ abstraction for pointer.
So basically you access the elements through dereferencing syntax:
(*it).bar = 0;
it->test = "";
for (it = fooset.begin(); it != fooset.end(); it++)
{
foo const & f = *it; //const is needed if it is C++11
//use f, e.g
std:: cout << f.bar <<", " << f.test << std::endl;
}
In C++11, you could do this instead:
for(foo const & f : fooset)
{
//use f, e.g
std:: cout << f.bar <<", " << f.test << std::endl;
}