C++ copy vector of objects to another - c++

I want to copy to vectors with the same size and same type one to another but after printing the value it seems like it doesn't work correctly or it doesn't want to copy all pointers to data in each object. Thanks for help
Here is code:
std::vector<Vehicle> vehicles(2);
std::vector<Vehicle> vehiclesCopy(2);
vehicles[0].setX_pos(3);
for(int i=0;i<vehicles.size();i++)
vehiclesCopy.push_back(vehicles[i]);
cout<<vehicles[0].getX_pos()<<endl;
cout<<vehiclesCopy[0].getX_pos()<<endl;
Output:
3
0
Here is the Vehicle code
class Vehicle
{
private:
unsigned int x_pos,y_pos,velocity;
char type;
public:
void vehicle(char inType,
unsigned int inX_pos,
unsigned int inY_pos,
unsigned int inVelocity)
{
type=inType;
x_pos=inX_pos;
y_pos=inY_pos;
velocity=inVelocity;
}
unsigned int getMaxPassengers(){
return maxPassengers;
}
unsigned int getX_pos(){
return x_pos;
}
unsigned int getY_pos(){
return y_pos;
}
unsigned int getVelocity(){
return velocity;
}
char getType(){
return type;
}
void setX_pos(unsigned int input){
x_pos=input;
}
void setY_pos(unsigned int input){
y_pos=input;
}
void setVelocity(unsigned int input){
velocity=input;
}
void setType(char input){
type=input;
}
};

You create two vectors with size 2. Then you push all elements from one vector to the other. You now have one unmodified vector and the other vector with 4 elements. Pushing two elements at the end wont have any effect on the first element (the one you print).
To copy vectors use simple assignment:
vehiclesCopy = vehicles;
Or if you want to use a loop (why would you?), assuming they both have correct size (they do in your example):
for(int i=0;i<vehicles.size();i++) {
vehiclesCopy[i] = vehicles[i];
}
PS: this answer isnt the whole truth. If vehiclesCopy is really just a copy of vehicles you should not first construct an empty vector and then copy it, but instead use the right constructor. See here for details (overload (6) is your friend here).

Related

How to store a reference to a C-style array in a class?

class Class
{
public:
Class(array[3][3]) //the constructor
{
this->array = array
}
array[3][3];
};
int main()
{
array[3][3] = {...initialization...};
Class object(array[3][3]);
}
I want to make an object, which uses the 2d array and modifies it. I know that C arrays are just pointers to an address, but I couldn't pass it in the constructor no matter how many *, & or [] I write.
The most clever thing I could think of is making an array of POINTERS in the class, and assigning each pointer, to the address of the original array's element via for loop, but then every time I want to modify, or read from the array in main, I have to write for example *array[2][1] = 3.
Any clever solution?
If I finally got the question correctly, you can use a reference to an array:
struct Class {
Class(int (&array)[3][3]) : array_(array)
{}
void set11(int value) {
array_[1][1] = value;
}
int (&array_)[3][3];
};
int main() {
int array[3][3]{};
Class object(array);
object.set11(99);
std::cout << array[1][1]; // Prints 99
}
If that's not what you want, please clarify your question.
Here's how to declare a pointer in your class that can point to the array in main.
class Class
{
public:
Class(int (*array)[3])
{
this->array = array;
}
int (*array)[3];
};
int main()
{
int array[3][3] = { ... };
Class object(array);
}

C++ set method: function 'setCost' not viable: 'this' argument has type 'const value_type'

I am not able to set value to a private member variable through set method. Getting error
member function 'setCost' not viable: 'this' argument has type 'const value_type' (aka 'const Position'), but function is not marked const
I have below code:
class Position {
public:
Position();
Position(int x, int y);
int getCost() const;
void setCost (int c);
private:
int x;
int y;
int cost;
};
void Position::setCost (int c){
this->cost = c;
}
class Board{
public:
Board();
Board(int N);
void shortestPath32 (Position start, Position end);
private:
int N;
char W[32][32];
};
void Board::shortestPath32 (Position start, Position end){
/* some code here */
set <Position> validMoves = getValidPositions(parent);
for(auto child =validMoves.begin(); child!=validMoves.end(); ++child ){
/*some code here ...*/
int c = 5
(*child).setCost(c);
}
}
}
Clearly if I declare setCost as void Position::setCost (int c) const, I am not able to do the assignment operation inside. Also, I looked into this thread for set method but wasn't helpful.
That's a limitation of std::set - its iterators always return const references. The rationale is - modifying an element in a set can change its position, so it's not allowed.
To modify an element in a set, the official process is to take it out of the set, modify it, and insert it back in.
Now if you know that modifying certain element properties won't affect its position, as a dirty workaround you can declare those mutable and the setter const:
class Position {
public:
Position();
Position(int x, int y);
int getCost() const;
void setCost (int c) const { cost = c; }
private:
int x;
int y;
mutable int cost;
};
An even dirtier solution is to cast away const, then you can modify anything (I feel dirty even bringing this up).
P.S. This issue can usually be avoided in the first place by choosing a structure that fits your needs better - for example std::map; you could refactor the code into Position and Cost:
class Position {
int x;
int y;
. . .
};
class Cost {
int cost;
. . .
};
std::map<Position,Cost> validMoves;
Then you will be able to modify Cost legally, while Position can remain const:
for(auto it =validMoves.begin(); it!=validMoves.end(); ++it){
it->second.setCost(c);
}
But that's a design choice that may depend on other factors not mentioned in the question...
As per the doc,
The value of the elements in a set cannot be modified once in the container (the elements are always const), but they can be inserted or removed from the container.
So you need to erase and re-insert in the set.
How to update an existing element of std::set?
As others have mentioned you could cast away the const but that wouldn't be the best solution and if you did that you would have to ensure that the cost isn't used in the sort. You could replace set with map and store the cost outside of your class.
You could then do something like the following...
void Board::shortestPath32 (Position start, Position end){
map<Position, int> validMoves; //getValidPositions(parent);
for(auto child=validMoves.begin(); child!=validMoves.end(); ++child ){
child->second=1; // NYI - replace 1 with the cost
}
}

C++: two vectors of pointers to the same structure, each differently sorted

I have a class with a structure of persons. Each person has its own name, primary ID and secondary ID. For effective searching I have implemented binary search. The problem is that I would like to effectively (better than O(n)) search persons not only by their primary ID, but also by their secondary ID. But the persons can be sorted only by one parameter. So I have thought if its possible to make two vectors of pointers to the persons structure, one sorted by their primary ID and the other one by their secondary ID.
For example, two persons: Mark Smith with primary ID 9845613 and secondary ID 1312469 and John Doyle, primary 3213444, secondary 2654722. So the first element of m_byPrim vector and second element of m_bySec vector should be pointing to John Doyle.
Is that even possible? Here is a part of the relevant code I have managed to write so far:
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <string>
using namespace std;
class CPersons
{
public:
bool AddPerson (const string &name,
unsigned int primID,
unsigned int secID);
private:
struct Person {
Person (const string & init_name,
unsigned int init_primID,
unsigned int init_secID)
: m_name (init_name), m_primID (init_primID), m_secID (init_secID){}
string m_name;
unsigned int m_primID;
unsigned int m_secID;
};
vector<Person*>m_byPrim;
vector<Person*>m_bySec;
};
bool CPersons::AddPerson (const string &name,
unsigned int primID,
unsigned int secID){
int positionPrim;
int positionSec;
return false;
}
int main ( void )
{
CPersons a;
a.AddPerson ( "Mark Smith", 9845613, 1324697 );
a.AddPerson ( "John Doyle", 3213444, 2654722 );
return 0;
}
The position integer is the result of my binary search function (position to which insert persons), I have managed to implement that successfully, so just assume that this position will be already initialized.
But my problem is how to implement the adding to the vector of pointers? I am still pretty new to the pointers (and C++ in general), so I don't know if my thought is valid and possible. Thank you for any tips & help.
edit: I forgot to mention that from STL containers I can use only vectors.
Instead of using sorted vectors, try using a std::map:
class CPersons
{
public:
bool AddPerson (const string &name, unsigned int primID, unsigned int secID);
private:
struct Person {
Person (const string & init_name, unsigned int init_primID, unsigned int init_secID)
: m_name (init_name), m_primID (init_primID), m_secID (init_secID) {}
string m_name;
unsigned int m_primID;
unsigned int m_secID;
};
map<unsigned int, Person*>m_byPrim;
map<unsigned int, Person*>m_bySec;
};
bool CPersons::AddPerson (const string &name, unsigned int primID, unsigned int secID){
p = new Person(name, primID, secID);
m_byPrim[primID] = p;
m_bySec[secID] = p;
return false;
}
The drawbacks of using a vector:
If you insert a person anywhere other than the end of the list, everything already in the vector has to "bubble down", being copied to its new position in the list.
As the vector grows, it will periodically need to be reallocated and the entire set of existing elements copied to the new underlying array.
The benefits of using a map:
The impact of adding new elements to the list is minimal
The interface for adding and looking up elements is more convenient and readable than finding things up in a sorted vector.
Since you can't use anything but vector, here's how your AddPerson function should look:
bool CPersons::AddPerson(
const string &name, unsigned int primID, unsigned int secID) {
// I'm assuming that the two functions below binary-search to get
// the positions where inserting the elements into the arrays would
// maintain their sorting
int positionPrim = getPositionPrim();
int positionSec = getPositionSec();
Person *person = new Person(name, primID, secID);
m_byPrim.insert(m_byPrim.begin() + positionPrim, person);
m_bySec.insert(m_bySex.begin() + positionSec, person);
return false;
}
You'll need to define a destructor as well because you're using dynamic memory:
CPersons::~CPersons()
{
for (const auto &i: m_byPrim) {
delete i;
}
}

Making an Array that stores pairs and or a class in c++?

I've looked for a while and none of the answers seem to fully fit my question, that or I've just hit a mental barrier.
I've made a class that has set and get methods and an output method called pairs, this works with two ints x+y and they each have set and get methods individually. I need to make a dynamic array based on the code below that can store these pairs. I'm not looking to be spoon fed I just want to know if my logic is correct and be pointed in the right direction.
class dynArray //a dynamic(ish) array class
{
public:
dynArray() : data(0), sz(0) { }
dynArray(int size) : sz(size) { data = new int[sz]; }
virtual ~dynArray() { if(data) delete [] data; } //destructor method
int& operator [] (int idx) { return data[idx]; } //operator overload!
int size() { return sz; }
private:
int * data;
int sz;
};
Pairs class
class pairs{
public:
pairs() : x(0), y(0) { }
void setX(int);
void setY(int);
void outputXY(int, int);
int getX();
int getY();
private:
int *x;
int *y;
};
void pairs::setX(int a)
{
x = &a;
}
void pairs::setY(int b)
{
y = &b;
}
int pairs::getX()
{
return *x;
}
int pairs::getY()
{
return *y;
}
void pairs::outputXY(int c, int d)
{
x = &c;
y = &d;
cout << "Number 1:" << c << " Number 2:" << d;
}
I'm very rusty with c++ so my logic has just vanished, I'm struggling to see how I would make an array that can store two ints within one element. Then i thought maybe I could make the pair class an array that stores two numbers in element 0 and 1 and then make an array of that class using the dynamic code, figuring out how to do this has stumped me though. All I really need is a helpful link or terms to be thrown at me as I really want to learn the code myself. Any help would be really appreciated, Thanks.
I would recommend using the STL library, in particular std::pair and some kind of container like std::lists or std::vectors. In order to implement some own, additional functionality, you may create your own class derived from those.
(Not enough "reputation" to post this answer as comment...)
If I correctly understood your issue, I'd suggest using a std::vector to store your elements since it will also spare you the memory management hassle
class dynArray //a dynamic(ish) array class
{
public:
dynArray() {}
dynArray(int size) { data.resize(size); /* Initialize with default-constructed elements */ }
pairs& operator [] (int idx) { return data[idx]; }
size_t size(){ return data.size(); }
private:
std::vector<pairs> data;
};
Just provide some insertion methods and you'll be good to go. Notice that the design will greatly simplify itself with the above solution.
Another solution as user236012 pointed out could be to use std::pair (specifically std::pair<int,int>) and just store the pairs in the vector.
If you intend to use the pairs class, be aware that your code is wrong:
void pairs::setX(int a)
{
x = &a; // Address of the actual parameter - address on the stack
}
therefore I'd suggest to either store plain values or use std::pair as suggested. There's really little point in storing pointers to integer values (they'd even be more expensive on many architectures).
A c-like way:
int * getPair(int idx)
{
return &data[idx*2];
}
void setPair(int idx, int * xy)
{
data[idx*2]=xy[0]; data[idx*2+1]=xy[1];
}

beginner question about arrays in structs in C++

I would like to create a struct and use it inside an other struct as an array. My problem is that I don't know how big array I would like to allocate, I will only know once I am in a function. I mean I would like to use [] instead of a pre-determined constant, like 10000.
I think if you look at my code it would be self-explanatory. Can you help me how to make this code work? Moreover it would help me a lot if you could tell me what is the name of the topic I am asking about (is it dynamic arrays?) and that where can I find articles/tutorials about this topic.
Here is the code with my broken way of thinking about arrays in structs.
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe keyframes[];
};
int main() {
keyframe_file my_file;
my_file.num_views = 1;
my_file.num_keyframes = 6;
my_file.keyframes = new keyframe[my_file.num_keyframes];
my_file.keyframes[0].a = true;
my_file.keyframes[0].b = 5;
my_file.keyframes[0].c = 9;
return 0;
}
Use a std::vector.
struct keyframe_file {
const int num_views;
const int num_keyframes;
std::vector<keyframe> keyframes;
};
int main() {
keyframe_file frame;
frame.keyframes.resize(...);
}
If it suits your purpose, an STL container (std::vector) is easily one of the best options - the less memory management you have to worry about, the better.
In any case, look at the struct definition Nawaz posted above - that's exactly how it should be. Dynamic arrays in C++ are simply pointers. You have, however, allocated the memory properly in your code, but you haven't freed it (so it's leaking). Since you allocated with new [] you will need to
delete [] my_file.keyframes;
in order to free the memory properly.
Resizing is another issue: with a smart implementation, array resizing can be an amortized O(1) operation which is nice. When you resize, it will always take you O(n) since you need to copy all the elements into a new array of different size, but if you do it half as much, it becomes O(1). That is, double the array each time you need to resize. Here is a very quick example
void resize()
{
if(numOfElementsInArray == sizeOfArray)
{
ArrayType * arr = new ArrayType[sizeOfArray*2]; // Allocate a double size array
for(int i=0;i<sizeOfArray;++i)
currentArray[i] = arr[i];
delete [] currentArray; // Free memory in old array
currentArray = arr; // Set the array to our new one
sizeOfArray *= 2; // Double the size
}
}
NOTE: The example above does not take into account space complexity; that said, if you have 5000 elements, and remove all but 5, this method with not shrink it (which is probably what you will want to do for all practical purposes)
Your code appears to be almost correct, except for two things:
keyframes needs to be a keyframe* rather than a keyframe[]
You forgot to delete the memory you allocated
That is incomplete type. In C++, array must be provided with size, and the size must be known at compile time itself.
You're using new, with which you should be using pointer.
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe *keyframes;
};
But std::vector<keyframe> is still a better choice, as #DeadMG already suggested.
By the way, the first two members are const in the struct, that means, they cannot be assigned value, as you're doing in your code. They must be initialized with values you want them to hold. That implies, now with vector, you've to include a constructor, to initialize the struct, as the struct is no more a POD.
struct keyframe_file {
const int num_views; //const member
const int num_keyframes; //const member
std::vector<keyframe> keyframes;
keyframe_file(int nviews, int nkeyframes)
: num_views(nviews), num_keyframes(nkeyframes), keyframes(nkeyframes){}
};
keyframe_file my_file(1,6); //done!
The suggested "Vector" is they safest way to do it.
But if it is only about making your code work (without resizing and stuff) the following should be working:
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe* keyframes;
};
int main()
{
keyframe_file my_file = {1, 6}; // initialization needed bcause of 'const int'
my_file.keyframes = new keyframe[my_file.num_keyframes];
for (int i = 0; i < my_file.num_keyframes; i++)
{
my_file.keyframes[i].a = true;
my_file.keyframes[i].b = 5 + i;
my_file.keyframes[i].c = 9 - i;
}
return 0;
}
somewhere in your code, when you are done using the array you have to call delete [] my_file.keyframes; as already mentioned.
There's a basic rule when using dynamic arrays in c++, especially when using it inside structs or classes, and it's to delete what you no longer need.
If you want to make your struct dynamic, it's easy, just replace the [] with * and the array will become dynamic, but it's not over yet, there is a lot of work.
You have to construct the array and destory it, and destoroying it is possible and useful noly with destructors, like this:
struct keyframe_file
{
const int num_views;
const int num_keyframes;
keyframe* keyframes;
~keyframe_file() // this is the destructor
{
delete[] keyframes;
}
};
Yet even that code isn't going to work at all, since you are assigning values to constants in variable my_file after creating it, it's illegal in c++, you should then use classes instead.
Using classes with dynamic arrays is very easy and interesting and makes your code very good, you don't have to know too much to do that, just learn what is a constructor, an initializer, destructor, private and public and go on with the following code:
#include <iostream>
using namespace std;
struct keyframe
{
bool a;
int b,c;
};
class keyframe_file
{
public:
keyframe_file(int NV, int NKF):num_keyframes(NKF),num_views(NV)
{
keyframes = new keyframe[num_keyframes];
}
~keyframe_file()
{
delete[] keyframes;
}
private:
const int num_views;
const int num_keyframes;
keyframe* keyframes;
};
int main()
{
keyframe_file my_file(1,6);
return 0;
}
This code works very well, it allows you to assign value to the constants num_views and num_keyframes for one time when creating the object (variable) my_file.
Remember, you are a C++ programmer, be proud of that, and use classes instead of structs and dynamic arrays instead of static ones.
Hope that's useful.
Use pointers and apply to your structure!
int *p;
p = new int;
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe *keyframes;
};
int main() {
keyframe_file my_file;
my_file.num_views = 1;
my_file.num_keyframes = 6;
for (int i = 0; i < my_file.num_keyframes; i++){
my_file.keyframes = new keyframe; //<---
}
my_file.keyframes[0].a = true;
my_file.keyframes[0].b = 5;
my_file.keyframes[0].c = 9;
return 0;
}