Pass reference of array of objects to function - c++

I'm trying to change a parameter of an object inside an array, but it seems like it's creating a new one when I pass it to the function.
I already saw similar questions and answers like this one, but it doesn't work for me, because I don't have a fixed array size in the final code.
I created a very short version of the code to show the problem.
#include <iostream>
using namespace std;
class Vect {
public:
Vect(int x, int y)
{
_x = x;
_y = y;
}
int _x;
int _y;
};
void ChangeX(Vect tests[], int size)
{
for (int i = 0; i < size; i++) {
tests[i]._x = 39;
}
}
int main()
{
Vect v1 = Vect(1,2);
Vect v2 = Vect(6,3);
cout << "Initial X: ";
cout << v1._x;
cout << "\n";
Vect vectors[2] = { v1, v2 };
cout << "Final X: ";
ChangeX(vectors, 2);
cout << v1._x;
return 0;
}
I expect the output to be:
Initial X: 1
Final X: 39
But in reality is:
Initial X: 1
Final X: 1
Also, using C++ vectors is not the solution for now. I'm running low on program memory usage and have a very small space for extra code.

Your issue has nothing to do with your function. It is updating the contents of the array correctly. There is no need to pass the array itself by reference.
The real problem is with the array itself. The statement Vect vectors[2] = {v1, v2}; makes copies of the v1 and v2 objects in the array. Your function is modifying the copies, and then afterwards you output values from the originals instead of the copies. So, your output does not change, since the function is not modifying the originals.
To accomplish what you are attempting, pass in an array of pointers instead, where the pointers are pointing at the original objects, not copies of them, eg:
#include <iostream>
class Vect {
public:
Vect(int x, int y){
_x = x;
_y = y;
};
int _x;
int _y;
};
void ChangeX(Vect* tests[], int size){
for(int i = 0; i < size; i++){
tests[i]->_x = 39;
}
}
int main()
{
Vect v1(1,2);
Vect v2(6,3);
std::cout << "Initial X:\n";
std::cout << v1._x << "\n";
std::cout << v2._x << "\n";
Vect* vectors[2] = {&v1, &v2};
ChangeX(vectors, 2);
std::cout << "Final X:\n";
std::cout << v1._x << "\n";
std::cout << v2._x << "\n";
return 0;
}
Live Demo
Otherwise, start out with an array to begin with, eg:
#include <iostream>
class Vect {
public:
Vect(int x, int y){
_x = x;
_y = y;
};
int _x;
int _y;
};
void ChangeX(Vect tests[], int size){
for(int i = 0; i < size; i++){
tests[i]._x = 39;
}
}
int main()
{
Vect vectors[2] = {Vect(1,2), Vect(6,3)};
std::cout << "Initial X:\n";
std::cout << vectors[0]._x << "\n";
std::cout << vectors[1]._x << "\n";
ChangeX(vectors, 2);
std::cout << "Final X:\n";
std::cout << vectors[0]._x << "\n";
std::cout << vectors[1]._x << "\n";
return 0;
}
Live Demo

Related

How I get center of points?

Problem: Create a vector consisting of point objects in a two-dimensional plane, calculate the average of the x and y coordinates of the point objects, and write a program that outputs the center of the points.
#include <iostream>
#include <string>
#include <iomanip>
#include <vector>
using namespace std;
class Point
{
public:
Point(std::string pname = NULL, int px = 0, int py = 0)
{
setName(pname); setX(px); setY(py);
}
std::string getName() { return name; }
int getX() { return x; }
int getY() { return y; }
void setName(std::string pname) { name = pname; }
void setX(int px) { x = px; }
void setY(int py) { y = py; }
private:
std::string name;
int x;
int y;
};
int main()
{
int a;
int counter = 0;
cout << "number of points" << endl;
cin >> a;
vector<Point> v1(a);
while (counter < a)
{
Point p1;
string tmp;
int tmp_x;
int tmp_y;
cout << "name of point" << endl;
cin >> tmp;
p1.setName(tmp);
cout << "position of point" << endl;
cin >> tmp_x >> tmp_y;
p1.setX(tmp_x);
p1.setY(tmp_y);
v1.push_back(p1);
cout << p1.getName() <<p1.getX() << p1.getY() << endl;
}
return 0;
}
this is an example of what I want (inline is keyboard input)
Number of points: 2
Name of point: p1
position of a point: 10 20
p1 (10, 20)
Name of point: p2
position of a point: 40 50
p2 (40, 50)
centor of points :(25.0, 35.0)
How should I approach averaging?
You don't need all of those #includes.
Pay attention to NULL in class constructor.
Loop continuation condition: a--. Variable counter is redundant.
Vector is dynamic data structure. You don't need to declare its size explicitly, in this exercise. Member-function push_back will do dirty work for you.
One more extra variable p1. Try:
v1.push_back( { tmp, tmp_x, tmp_y } );
Finally...
double // if precision is necessary
total_x{}, total_y{};
for ( auto& point : v1 ) {
total_x += point.getX();
total_y += point.getY();
}
std::cout << "Average X: " << total_x / v1.size()
<< "\nAverage Y: " << total_y / v1.size();
return EXIT_SUCCESS;

How to use c++ structure array like flexible?

What should I do if I want to use the structure array flexibly?
I made my code like below, and tried Triangle and Rectangular..
Triangle was success but when i tried Rectangular I got error messages.
struct C2D {
double x, y;
};
class Polygon {
int point;
std::vector<C2D> arr;
public:
Polygon(int point_, C2D arr_[]) : arr(point_) {
point = point_;
memcpy(arr.data(), arr_, sizeof(C2D) * point);
};
void print() const {
for (int i = 0; i < point; i++) {
cout << arr[i].x << " " << arr[i].y << endl;
}
};
};
int main() {
int point;
C2D c2d[3];
cout << "point : ";
cin >> point;
cout << endl;
vector<C2D>c2d(point);
for (int i = 0; i < point; i++) {
cout << i + 1 << "x : ";
cin >> c2d[i].x;
cout << i + 1 << "y : ";
cin >> c2d[i].y;
cout << endl;
}
cout << endl;
Polygon p(point, c2d);
p.print();
return 0;
}
The problem is that you use the same name for
C2D c2d[3];
and
vector<C2D>c2d(point);
However, your code has several other issues such as using C-arrays in C++. Consider using std::vector, e.g., like this:
#include <iostream>
#include <vector>
struct C2D {
double x, y;
};
class Polygon {
std::vector<C2D> coordinates;
public:
explicit Polygon(const std::vector<C2D> &coords) : coordinates(coords) {}
void print() const {
for (const auto &c : coordinates) {
std::cout << c.x << " " << c.y << "\n";
}
}
};
int main() {
int point;
std::cout << "point : ";
std::cin >> point;
std::cout << "\n";
std::vector<C2D> coordinates(point);
for (int i = 0; i < point; i++) {
std::cout << i + 1 << "x : ";
std::cin >> coordinates[i].x;
std::cout << i + 1 << "y : ";
std::cin >> coordinates[i].y;
std::cout << "\n";
}
std::cout << "\n";
Polygon p(coordinates);
p.print();
}
As per your code, you declared variable name c2d one is C2D array type and the other is a vector of C2D what is the purpose of two variable names are the same you declared. My suggestion is to allocate c2d variable based on point count and pass to the polygon. As per my understanding change your polygon constructor with parameter array or vector and passing the corresponding argument to the constructor.

Getting segmentation fault (core dumped) error when declaring a int variable

I was trying to create vector like class. Here is my code
#include <bits/stdc++.h>
using namespace std;
template<class t>
class vec{
t *start;
int size=0;
public:
void add_value(t a){
*(start+(sizeof(t)*size)) = a;
cout << (start+(sizeof(t)*size))<< " = "<< *(start+(sizeof(t)*size))<<endl;
size++;
// cout << start<< endl;
}
void operator [](int i){
cout << (start+(sizeof(t)*i))<< " = "<< *(start+(sizeof(t)*i))<<endl;
}
int length(){
return size;
}
};
int main(){
vec<int> t;
cout << t.length()<<endl;
t.add_value(8);
t.add_value(10);
cout << t.length()<<endl;
t[1];
}
This gives me correct output.
0
0x7fff0fe9b5d0 = 8
0x7fff0fe9b5e0 = 10
2
0x7fff0fe9b5e0 = 10
But when declare a int variable in main function like.
int main(){
int i=0; //newline
vec<int> t;
cout << t.length()<<endl;
t.add_value(8);
t.add_value(10);
cout << t.length()<<endl;
t[1];
}
output.
0
Segmentation fault (core dumped)
I also tried printing address of start variable and new int variable int those are different.
You probably want something like this:
#include <iostream>
using namespace std;
template<class t>
class vec {
t* start = new t[100]; // initialize the pointer (fixed size of 100, to be improved)
int size = 0;
public:
void add_value(t a) {
*(start + size) = a;
size++;
}
t operator [](int i) { // should return a t instead of a void
return *(start + i);
}
int length() {
return size;
}
};
int main() {
vec<int> t;
cout << "t.length() = " << t.length() << endl;
t.add_value(8);
t.add_value(10);
cout << "t.length() = " << t.length() << endl;
// display all values in t
for (int i = 0; i < t.length(); i++)
{
cout << "t[" << i << "] = " << t[i] << endl;
}
}
All multiplication by sizeof(t) have been removed, because pointer arithmetic already does this for you.
This very poor and minimalist example works as you expect, but the maximum number of elements you can store in the class is 100. I leave the improvement as an exercise to you.
BTW there are many other improvements you need to do, especially you need a destructor and possibly the rule of three
Note:
You should replace all instances of *(start + x) with start[x] which does exactly the same thing but which is more idiomatic and more readable.

Custom defined type for cv::Mat in OpenCV

I want to create an array using cv::Mat with my custom defined type. Here is my code:
typedef struct{
int x;
int y;
float prob;
}CellXY;
void main(){
cv::Mat_<CellXY> map(10, 10);
std::cout << "Width = " << map.cols << ", Height = " << map.rows << std::endl;
std::cout << "### Assignment ###" << std::endl;
for (int j=0; j<map.rows; j++){
for (int i=0; i<map.cols; i++){
map.at<CellXY>(j, i).x = i;
map.at<CellXY>(j, i).y = j;
map.at<CellXY>(j, i).prob = (float)(i + j * map.cols);
std::cout << map.at<CellXY>(j, i).prob
<< " (" << map.at<CellXY>(j, i).x
<< "," << map.at<CellXY>(j, i).y
<< ")\t";
}
std::cout << std::endl;
}
std::cout << "### Display ###" << std::endl;
for (int j=0; j<map.rows; j++){
for (int i=0; i<map.cols; i++){
std::cout << map.at<CellXY>(j, i).prob
<< " (" << map.at<CellXY>(j, i).x
<< "," << map.at<CellXY>(j, i).y
<< ")\t";
}
std::cout << std::endl;
}
map.release();
}
However results between "Assignment" and "Display" sections are not the same:
How do I make these results the same?
This is becasue OpenCV doesn't know the DataType of your class. You need to a specialization for it, something like:
typedef struct {
int x;
int y;
float prob;
}CellXY;
// Add this!!!!!!
namespace cv {
template<> class DataType<CellXY>
{
public:
typedef CellXY value_type;
typedef value_type work_type;
typedef value_type channel_type;
typedef value_type vec_type;
enum { generic_type = 0,
depth = CV_32F, // Might cause problems... I'm saying it's all made of floats (and not 2 int a 1 float)
channels = 3,
fmt = (int)'p',
type = CV_MAKETYPE(depth, channels)
};
};
}
void main() {
...
}
But, in general, I think it's better to avoid messing up with these implementation details, and just use a better data structure. The recommendation is: use Mat only for primitive types. In fact, you can't use it in other OpenCV functions anyway...
Here a few ways to solve your problem:
Use another data structure: e.g. a std::vector<std::vector<CellXY>> or an "unrolled" std::vector<CellXY>
Make a class CellXYMatrix which deals with storing the CellXY:
class CellXYMatrix
{
std::vector<CellXY> _mat; // your matrix of CellXY
int _r; // rows
int _c; // cols
public:
CellXYMatrix(int rows, int cols) : _r(rows), _c(cols), _mat(rows * cols) {};
void set(int row, int col, const CellXY& cell) {
_mat[row * _c + col] = cell;
}
CellXY& get(int row, int col) {
return _mat[row * _c + col];
}
}
You can eventually overload operator() to make the access similar to OpenCV Mats.
If the x and y fields in CellXY refer to the matrix position, why do you need them? You can simply have a Mat1f (aka Mat_<float>) for your probabilities, and x,y are the position in the matrix.

c++ myVector.erase(myVector.begin()) works but not in my object

How come my ptBucket.getBucket().at(icnt) works but my ptBucket.getBucket().erase() and ptBucket.getBucket().begin() do not work.
Code is below.
I want to have an object that contains a vector of pointers. The pointers will point to dynamically allocated objects and I want to clean up at the end. I seem to be screwing up the extra level of indirection.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
class Pt{
int x_;
int y_;
public:
Pt(int x, int y);
int getX();
int getY();
};// end class pt
Pt::Pt(int x, int y){
x_ = x;
y_ = y;
}
int Pt::getX(){
return x_;
}
int Pt::getY(){
return y_;
}
class BucketOfPts{
vector<Pt*>bucket;
public:
void addToBucket(Pt *pt);
vector<Pt*> getBucket();
};
void BucketOfPts::addToBucket(Pt *pt){
bucket.push_back(pt);
}
vector<Pt*> BucketOfPts::getBucket(){
return bucket;
}
int main()
{
cout << "this works" << endl;
vector<Pt*> points;
for(unsigned icnt =0;icnt<5;icnt++)
points.push_back(new Pt(icnt,icnt));
for(unsigned icnt =0;icnt<5;icnt++)
cout << "x of icnt["<<icnt<<"] "<< points.at(icnt)->getX() << endl;
for(unsigned icnt =0;icnt<5;icnt++)
{
/*** this simple construct does work ***********/
points.erase(points.begin());
/*** this simple construct does work ***********/
cout << "size: " << points.size() << endl;
}
cout << "this does NOT work" << endl;
BucketOfPts ptBucket = BucketOfPts();
for(unsigned icnt =0;icnt<5;icnt++)
ptBucket.addToBucket(new Pt(icnt,icnt));
for(unsigned icnt =0;icnt<5;icnt++)
cout << "x of icnt["<<icnt<<"] "<< ptBucket.getBucket().at(icnt)->getX() << endl;
// how come ptBucket.getBucket.at() above works
// but ptBucket.getBucket.begin() below does not work??
cout << "going to try to erase" << endl;
for(unsigned icnt =0;icnt<5;icnt++)
{
cout << "going to erase icnt: " << icnt << endl;
/*** this simple construct does NOT work ***********/
ptBucket.getBucket().erase(ptBucket.getBucket().begin());
/*** this simple construct does NOT work ***********/
cout << "size: " << ptBucket.getBucket().size() << endl;
}
return 0;
}
here's my output:
this works
x of icnt[0] 0
x of icnt[1] 1
x of icnt[2] 2
x of icnt[3] 3
x of icnt[4] 4
size: 4
size: 3
size: 2
size: 1
size: 0
this does NOT work
x of icnt[0] 0
x of icnt[1] 1
x of icnt[2] 2
x of icnt[3] 3
x of icnt[4] 4
going to try to erase
going to erase icnt: 0
Segmentation fault (core dumped)
As is, your getBucket() function returns a copy of the vector<Pt*> bucket; member. Thus the statement
ptBucket.getBucket().erase(ptBucket.getBucket().begin());
just operates with two unrelated copies of that vector.
To get the vector member in the class instance affected, you need to return a reference to this member
class BucketOfPts{
public:
// ...
vector<Pt*>& getBucket();
// ^ <<<<<<
};
vector<Pt*>& BucketOfPts::getBucket() {
// ^ <<<<<<
return bucket;
}
`