Suppose I have a class MyClass:
class MyClass{
private:
vector<vector<float>> _vec;
public:
MyClass(vector<vector<float>> arg){
_vec = arg;
// shape is a 2-element vector where shape[0] = #elems in _vec
// and shape[1] = #elems in _vec[0]
shape.push_back(_vec.size());
shape.push_back(_vec.begin()->size());
}
vector<int> shape;
};
Now suppose I have a member function func of MyClass:
MyClass MyClass::func(){
MyClass res(this->_vec);
// delete the first element of `res._vec`
res._vec.erase(res._vec.begin());
return res;
}
Now, if I do:
MyClass A = {{1, 2}, {3, 4}}; // A.shape[0] = 2, A.shape[1] = 2
MyClass B = A.func(); // B._vec is {{3, 4}} but B.shape[0] is still 2
Here, B._vec changes, but B.shape is not "updated" accordingly.
How can I dynamically update MyClass.shape as and when MyClass._vec changes? One way to do this is to instead make a member function MyClass.shape() which whenever called checks the current MyClass._vec. But is there a better way of doing this?
How can I dynamically update MyClass.shape as and when MyClass._vec changes?
Write a function that updates shape, and call it whenever you change _vec.
But is there a better way of doing this?
Don't use shape member at all, but instead call _vec.size() and _vec.begin()->size() when you need those values. This way there is nothing to update, no redundant duplicate waste of memory, and the user of the class cannot break the apparently missing invariant.
Related
I have the following class for points:
class MyPoint
{
public:
// Constructor
MyPoint(double, double, double);
// Destructor
virtual ~MyPoint(){};
protected:
private:
double x;
double y;
double z;
};
I would like to create a vector of myPoints to store some data:
vector <MyPoint> vectorOfPoints
for (int i = 0; i < 10 ; i++)
{
vectorOfPoints.push_back(MyPoint(1,2,3));
}
And I would like to create a class called myFaces to store the address of the points that make up a face.
e.g.,
Face A is built with vectorOfPoints[0], vectorOfPoints[2], vectorOfPoints[5] and vectorOfPoints[6].
How can I pass a vector with the addresses of the above entries to the class myFace?
class myFace
{
public:
// Constructor
myFace(int, vector<std::shared_ptr<Point> > );
// Destructor
virtual ~myFace(){};
protected:
private:
int nPointsInFace_;
vector<std::shared_ptr<Point> > refToPointsThatMakeUpThisFace_;
};
Would really appreciate the help!
Face A is built with vectorOfPoints[0], vectorOfPoints[2], vectorOfPoints[5] and vectorOfPoints[6].
You want indexes. So store that!
class myFace
{
vector<size_t> indexes_;
public:
myFace(vector<size_t>) ...
};
You don't need nPointsInFace_ because its the size of indexes_.
You can use a smaller type if you know you dont need so many, like uint16_t.
You avoid messing with pointers (and shared_ptr which is overkill for single 3D points).
You can do checked accesses.
Probably the easiest answer is to change your vector of points to a vector of pointers to points. Something like this:
vector <std::shared_ptr<MyPoint>> vectorOfPoints;
for (int i = 0; i < 10 ; i++)
{
vectorOfPoints.push_back(std::make_shared<MyPoint>(1,2,3));
}
Now you can very easily just cherry pick whichever points you want to pass to your myFace constructor. Using managed pointers like std::shared_ptr is an all-or-nothing proposition.
What if I put something like
class myFace
{
public:
// Constructor
myFace(int, vector<myPoint*>);
// Destructor
virtual ~myFace(){};
protected:
private:
int nPointsInFace_;
vector<myPoint*> refToPointsThatMakeUpThisFace_;
};
After initializing the vectorOfPoints. If I can
std::vector<Point*> listOfPoints (4);
listOfPoints[0] = vectorOfPoints[0]
listOfPoints[1] = vectorOfPoints[2]
listOfPoints[2] = vectorOfPoints[5]
listOfPoints[3] = vectorOfPoints[6]
Face myFace (4, listOfPoints);
This should create a face with the address of the vectorOfPoints, no?
More classes will have pointers the vectorOfPoints, is makes sense to use a shared_ptr, right?
Let's take an example where we need to insert the vector returned from a function to another vector:
const std::vector<int> getvec(){
return {1, 2, 3};
}
// in main...
std::vector<int> foo{ 11, 12 };
auto bar = getvec();
foo.insert(foo.end(), bar.begin(), bar.end());
The fact that the bar variable needs to be referenced twice in the insert() method makes it necessary to have the vector stored as a variable (we could otherwise do foo.myinsert(getvec()) should there be such an interface).
It is a bit annoying to me that in such a case, we need to introduce a variable foo in the main scope which is not meant to be used again in the rest of the code, as it occupies the memory and also pollutes the namespace. Especially a problem if we are talking about with a large "temporary" object.
Is there a standard approach to deal with that? We could define a function that take the "temporary" object only once so that we can directly feed function output to it, but would be difficult to manage if we need to define such function for every similar scenario. Also as in this example we are not able to define a member function for vector class.
Alternatively what using braces to limit the scope of the "temporary" part of the insertion but I would like to know if any caveat here.
vector<int> foo{ 11, 12 };
{ // extra brace here
auto bar = getvec();
foo.insert(foo.end(), bar.begin(), bar.end());
} // extra brace here
Not the prettiest solution, but you could use a temporary lambda instead of a separate function, and declaring and invoking it in the same statement avoids the need for braces to limit its scope.
const std::vector<int> getvec(){
return {1, 2, 3};
}
// in main...
std::vector<int> foo{ 11, 12 };
[&](const auto &bar){ foo.insert(foo.end(), bar.begin(), bar.end()); }(getvec());
Live Demo
You could write a little template function to do this, which takes a vector by const reference (which can bind to a temporary and extend its lifetime):
template<typename C>
void append(std::vector<C> &invec, const std::vector<C> &temp)
{
invec.insert(std::end(invec), std::begin(temp), std::end(temp));
}
and this could be used for all other types of vectors. Then you can call it like this:
append(foo, getvec());
Working demo here.
You can make strings of other things than char. Thru basic_string<int> you can access string::append ( and other things )
using strint = std::basic_string<int>;
strint getVec () {
return { 1, 2, 3, 4, 5 };
}
strint foo{ 6, 7 };
foo += getVec();
https://godbolt.org/z/h4naTa
So what I am trying to achieve is to return a pointer to a 2D array from the function so it could accessed in main(). I know there are some C++ libraries that does it for you like std::vector but I am trying to avoid dynamic memory allocation since I am working on embedded board (STM32) so I will stick to just normal pointers and arrays. (ALSO for some reason I can't use std::array in KEIL uVision, which is also why I am forced to work with pointers/arrays)
In addition, I understand that returning a pointer to a local array int arr[2][2] defined inside the function is not a good idea since it will no longer be valid after the function returns, which is why I creating test_array, declaring it inside a class and defining it in a function (acting as a global variable) so I assume this shouldn't be a problem. What do you guys think? However, doing it this way gives an error "Excess elements in scalar initializer"
#include <iostream>
#include "file.hpp"
int main() {
myClass class_object;
class_object.value = class_object.foo();
}
//file.hpp
#include <stdio.h>
class myClass{
int array[2][2];
int (*foo())[2];
int (*value)[2];
int test_array[2][2]; //declaring here!
};
//file.cpp
#include "file.hpp"
int (*myClass::foo())[2]{
test_array[2][2]={ {10,20}, {30, 40} }; //defining here - ERROR!!
int arr[2][2]= {
{1, 10},
{20, 30}
};
return arr;
}
The immediate problem:
test_array[2][2]={ {10,20}, {30, 40} }; //defining here - ERROR!!
is not defining. test_array was defined up in myClass. This is attempting to assign to a single element of test_array, specifically [2][2] which does not exist. What particularly offends the compiler is not the out of bounds access, but that ={ {10,20}, {30, 40} }; is trying to stuff an array into a single array element. The compiler is expecting a single number, so four numbers is definitely in excess.
Unfortunately I don't know of a good way to do what you want to do. You can initialize an array with an initializer list, but you can't assign from one.
So
class myClass{
public:
myClass();
void foo();
int test_array[2][2]; //declaring here!
};
// you can do this:
myClass::myClass(): test_array{ {10,20}, {30, 40} }
{
}
void myClass::foo()
{
// but you can't do this:
test_array = { {10,20}, {30, 40} };
}
Depending on what you do with test_array, initializing in the constructor may work for you. If you have to reset the array on every call to foo, perhaps an Automatic variable is a better fit for you
void myClass::foo()
{
int temp_array[2][2] = { {10,20}, {30, 40} };
// use temp_array
// maybe copy temp_array to test_array with good ol' memcpy here if you
// need to carry the state for some reason.
}
To silence the elephant in the room and gain access to std::array, give this a try. Note: I've never done this. It could be an utter freaking disaster for all I know, so take it with a grain of salt.
If you really want to work with C-Array, use typedef to have normal syntax:
class myClass{
public:
using array2 = int[2][2];
myClass() {
test_array[0][0] = 0;
test_array[0][1] = 1;
test_array[1][0] = 2;
test_array[1][1] = 3;
}
const array2& getArray() const { return test_array; }
array2& getArray() { return test_array; }
private:
array2 test_array;
};
I have a function which makes use of an unordered_map and its only this function in my class which uses it:
void my_func(){
static std::unordered_map<int,int> my_map;
//I only want this to be done the first time the function is called.
my_map[1] = 1;
my_map[2] = 3;
//etc
}
How can I insert the elements in to my static unordered_map so that they only get inserted the first time my function is called (just like the memory allocation is only made the first time)?
Is it possible?
In C++11 (which you're presumably using, otherwise there wouldn't be an unordered_map), containers can be populated by a list initialiser:
static std::unordered_map<int,int> my_map {
{1, 1},
{2, 3},
//etc
};
Historically, the cleanest way would be to call a function that returns a populated container:
static std::unordered_map<int,int> my_map = make_map();
If I have a class like so (forgive the rough syntax):
class Z{
public:
void method1();
void method2(vector<X>& v);
void method3(vector<X>& v);
private:
std::vector<X> myvec;
}
and basically I want to pass myvec from method1() through method2() to method3() where it will be modified. If my method1() looks like this:
void Z::method1(){
vector<X> v = z::myvec; //What do I have to do with this line so that the changes
method2(v); //made to v in method3() are permanent and not lost once
} //method1() returns?
void Z::method2(vector<X>& v){
method3(v);
}
//Modify vector<X> myvec
void Z::method3(vector<X>& v){
v.push_back(<something>);
}
How could I change the vector in method3() so that once method1() returns, the changes made to the vector are permanent and not lost?
Just make v a reference:
vector<X>& v = myvec;
or simply pass myvec itself:
method2(myvec);
Why not just allow method3 to use the class' member data directly? That's a perfectly normal thing to do.
void Z::method3(){
myvec.push_back(<something>);
}
But if you really want to do it your way (and I would advise against it as it's so idiosyncratic), replace your first commented line with
vector<X>& v = z::myvec;
I dont know why you exactly wanted this flow, method1()-->method2()-->method3(). If this is something that is not intentional you can directly use data member myvec in method3(). But I am sure this could not be the case, there must be a use case because of which you are using it.
for the other way, you can modify, method1() in this way.
void Z::method1(){
method2(z::myvec);
}
and keep rest of the function as it is.
Actually what's happening in your case is in your method1() you are actually creating new object and passing that new object with reference so all that changes is being made to that new vector not the original vector.
vector<X> v = z::myvec; // this creates new object.
You test is with debugging.
please let me know if this answers your doubt.