I have a struct which contains a reference to a vector.
I then create a vector of this struct.
I create three three instances of this struct in this vector.
I then erase the second instance of the struct in the vector.
This apparently causes the contents of testData2 to become the same as the contents of testData3!?
How do I stop this from happening? Is there something I should put in the destructor of the struct to stop this from happening?
Or is what I am doing here terribly bad and if so, why?
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
struct TESTSTRUCT
{
int &testInt;
std::vector<int> &testVector;
TESTSTRUCT(int &testIntInput, std::vector<int> &testVectorInput)
:testInt(testIntInput), testVector(testVectorInput) {}
TESTSTRUCT(const TESTSTRUCT &source)
:testInt(source.testInt), testVector(source.testVector) {}
TESTSTRUCT &operator=(const TESTSTRUCT &source)
{
testInt = source.testInt;
testVector = source.testVector;
return *this;
}
virtual ~TESTSTRUCT(){}
};
int main()
{
std::vector<int> testData1;
std::vector<int> testData2;
std::vector<int> testData3;
int a = 1;
int b = 2;
int c = 3;
testData1.push_back(10);
testData1.push_back(20);
testData1.push_back(30);
testData2.push_back(40);
testData2.push_back(50);
testData2.push_back(60);
testData3.push_back(70);
testData3.push_back(80);
testData3.push_back(90);
std::vector<TESTSTRUCT> *structVector = new std::vector<TESTSTRUCT>();
structVector->push_back(TESTSTRUCT(a, testData1));
structVector->push_back(TESTSTRUCT(b, testData2));
structVector->push_back(TESTSTRUCT(c, testData3));
std::cout<<&testData1[0]<<std::endl;
std::cout<<&testData2[0]<<std::endl;
std::cout<<&testData3[0]<<std::endl;
std::cout<<testData1[0]<<std::endl;
std::cout<<testData2[0]<<std::endl;
std::cout<<testData3[0]<<std::endl;
structVector->erase(structVector->begin()+1);
std::cout<<testData1[0]<<std::endl;
std::cout<<testData2[0]<<std::endl;
std::cout<<testData3[0]<<std::endl;
std::cout<<&testData1[0]<<std::endl;
std::cout<<&testData2[0]<<std::endl;
std::cout<<&testData3[0]<<std::endl;
return 0;
}
Output:
00711220
00711258
00717C68
10
40
70
10
70
70
00711220
00711258
00717C68
Press any key to continue . . .
EDIT:
This here is an example from a larger program. The instances of the struct are for things I want a renderer to draw, and those things can change their position (and hence where the renderer should draw them).
The issue is not immediately visible. Have a look at the equality operator of TESTSTRUCT :
TESTSTRUCT &operator=(const TESTSTRUCT &source)
{
testInt = source.testInt;
testVector = source.testVector;
return *this;
}
The testVector in this will obtain a copy of source.testVector.
Now, the structVector in main contains three instances of TESTSTRUCT, each bound to its own std::vector<int> via a reference. When you call structVector->erase(structVector->begin()+1);, TESTSTRUCT(b, testData2) is removed from the structVector.
The specification of erase says that all the vector's elements after the requested erasing position are shifted down (in terms of position) in order for the vector to be memory-contiguous. I don't know if the standard specifies anything about how erase needs to be implemented when it comes to copying, but in my implementation (g++), operator= is called. This means that the vector stored via reference inside the TESTSTRUCT instance referenced by the iterator structVector->begin()+1 (so, effectively, structVector[1]) gets the contents of structVector[2]. And because it's a reference, it's essentially the same thing as testData2 from main, which explains why its content is exactly the same as testData3.
This is valid, however, as you can see yourself, avoiding such code makes sense when debugging.
You are over using references (somewhat incorrectly). Your TESTSTRUCT objects contains references to testdata1, testdata2 and testdata3. So when you modify structVector, previous two vectors also get modified. So when you erase second element from structVector, the third element takes it's position. So the internal elements, i.e. the testdata2 is also replaced with testdata3in main, as their references are contained in the struct.
Related
So I had a coding interview a week ago for an advanced C++ position where the question was basically asking me to swap two insantiations of a class called Line. Which is basically just a container for a std::vector<int>. But the equals operator was private so I couldn't swap the variables normally. It also had a weirdly unimplemented function called "swap" that was just there. No implementation or anything. I have spent the past week going over the question in my head having no idea how to tackle this. I'm by no means a c++ expert, but I am also not a complete newbie. I however have not come up with anything useful. Was it asking me to subclass the Line class? Manipulate pointers? I have no clue.
Before closing and downvoting the question please note that the main and Line class were unmodifiable
Here is the code I got:
#include <iostream>
#include <vector>
// Unmodifiable Code:
class Line {
std::vector<int> people;
void operator=(Line& other);
public:
Line(std::vector<int> p) : people(p) {}
void print_ids() {
for (auto i = this->people.begin(); i != this->people.end(); ++i) {
std::cout<<*i;
}
}
void swap(Line& other);
};
// End Unmodifiable Code.
// THIS IS WHAT I HAD TO IMPLEMENT:
void switch_lines(Line& line1, Line& line2) {
// TODO: This.
}
// Unmodifiable Code
int main(int argc, char** argv) {
std::vector<int> people1 = std::vector<int>();
people1.push_back(12);
people1.push_back(3);
people1.push_back(4);
people1.push_back(5);
std::vector<int> people2 = std::vector<int>();
people2.push_back(7);
people2.push_back(8);
people2.push_back(9);
auto line1 = Line(people1);
auto line2 = Line(people2);
std::cout<<"The Lines Before:\n";
line1.print_ids();
line2.print_ids();
switch_lines(line1, line2);
std::cout<<"The Lines After:\n";
line1.print_ids();
line2.print_ids();
}
// End Unmodifiable Code.
Here is what I can think of and why it can't work:
Swapping the internal vectors: doesn't work because the people field is inaccessible and the Line class is unmodifiable
Swapping the Line objects themselves: I have tried swapping their internal addresses but all I can change is newly created pointers to the objects, not the original variables
Subclassing the Line class: I have tried, but it doesn't help because I can't access the people field or the = operator.
The challenge was to modify the switch_lines method.
Simply call the member function swap there:
line1.swap(line2);
Swap two objects without using an equals operator
If you need to implement Line::swap, you can simply std::swap each sub object:
void Line::swap(Line& other) {
std::swap(people, other.people);
}
Sorry for the confusing title, basically I have created two classes, one is an object, and the other being a box that contains an array of such objects. so what I want to do is create a function/constructor inside the object class that takes in an array of ints and stores them inside the box. I want to be able to call this function through the box class constructor to initialize these objects. So ive tried something like below but it isnt working at all, since only the first value of the array gets passed through. What am I doing wrong?
#include <iostream>
#include <string>
class object{
string objectName;
int values[];
public:
void createObject(int[]);
}
class Box{
object objects[100];
public:
Box();
}
Box::Box (void){
int array1[2];
int array2[15];
object[1].createObject(array1);
object[2].createObject(array2);
}
Object::Object(int Values[]){
values = Values;
}
You should really use std::vector. The problem with arrays is that they decay to pointers when passed as arguments to functions. As a consequence, If you want to store a private copy of the elements you are forced to use heap-allocated objects and consequently do memory management by hand (with all the pain it causes).
It is much better to rely on data members that permit applying the rule of zero.
Here's a tentative solution:
#include <iostream>
#include <string>
#include <vector>
class object {
public:
object(std::vector<int> const& v, std::string const& object_name): v_(v.begin(), v.end()), object_name_(object_name) {}
private:
std::vector<int> v_;
std::string object_name_;
};
class box {
public:
box(std::vector<object> const& objects): objects_(objects) {};
private:
std::vector<object> objects_;
};
I recommend you instead use a std::vector. Arrays don't really work well being passed to functions. When you define Object::Object(int Values[]) you are simply passing the first element of this array by value. If you were to use vectors, the function would look like this:
Object::Object(std::vector<int> &Values):
values(Values)
{
}
The problem with the code is in your thinking on what the array is. In C++, all an array is, is a memory pointer. The language allows you to pass an index into the array pointer to access whatever chunk of data lives at that index.
Whenever you pass arrays between functions or classes, pass the array name only. It will be interpreted as a pointer, and won't copy any data. When you do this, you must also pass the length of the array.
Granted, most people stick with vector<> because it's easier, takes care of memory leaks (mostly) and is VERY efficient. But I like doing it myself. It's good for you. I would try:
#include <iostream>
#include <string>
class Object
{
string _objectName;
int *_values;
int _myLength;
Object();
~Object();
void createObject(int *pValues, int arrLength);
}
class Box
{
_Object objects[100];
Box();
}
Box::Box(void) {
int array1[2];
int array2[15];
object[1].createObject(array1, 2);
object[2].createObject(array2, 15);
}
Object::Object() {
_values = null_ptr;
_myLength = 0;
}
Object::~Object() {
delete[] _values;
}
void Object::createObject(int *pvalues, int arrLength) {
_myLength = arrLength;
_values = new int[_myLength];
for(int ndx=0; ndx<arrLength; ndx++) {
_values[ndx] = pvalues[ndx];
}
}
-CAUTION-
I just adapted your code you provided, and added some conventions. There are a couple places in the code where I'm not sure what the purpose is, but there you go. This should give you a good head start.
How do I get the position of an element inside a vector, where the elements are classes. Is there a way of doing this?
Example code:
class Object
{
public:
void Destroy()
{
// run some code to get remove self from vector
}
}
In main.cpp:
std::vector<Object> objects;
objects.push_back( <some instances of Object> );
// Some more code pushing back some more stuff
int n = 20;
objects.at(n).Destroy(); // Assuming I pushed back 20 items or more
So I guess I want to be able to write a method or something which is a member of the class which will return the location of itself inside the vector... Is this possible?
EDIT:
Due to confusion, I should explain better.
void Destroy(std::vector<Object>& container){
container.erase( ?...? );
}
The problem is, how can I find the number to do the erasing...? Apparently this isn't possible... I thought it might not be...
You can use std::find to find elements in vector (providing you implement a comparison operator (==) for Object. However, 2 big concerns:
If you need to find elements in a container then you will ger much better performance with using an ordered container such as std::map or std::set (find operations in O(log(N)) vs O(N)
Object should not be the one responsible of removing itself from the container. Object shouldn't know or be concerned with where it is, as that breaks encapsulation. Instead, the owner of the container should concern itself ith such tasks.
The object can erase itself thusly:
void Destroy(std::vector<Object>& container);
{
container.erase(container.begin() + (this - &container[0]));
}
This will work as you expect, but it strikes me as exceptionally bad design. Members should not have knowledge of their containers. They should exist (from their own perspective) in an unidentifiable limbo. Creation and destruction should be left to their creator.
Objects in a vector don't automatically know where they are in the vector.
You could supply each object with that information, but much easier: remove the object from the vector. Its destructor is then run automatically.
Then the objects can be used also in other containers.
Example:
#include <algorithm>
#include <iostream>
#include <vector>
class object_t
{
private:
int id_;
public:
int id() const { return id_; }
~object_t() {}
explicit object_t( int const id ): id_( id ) {}
};
int main()
{
using namespace std;
vector<object_t> objects;
for( int i = 0; i <= 33; ++i )
{
objects.emplace_back( i );
}
int const n = 20;
objects.erase( objects.begin() + n );
for( auto const& o : objects )
{
cout << o.id() << ' ';
}
cout << endl;
}
If you need to destroy the n'th item in a vector then the easiest way is to get an iterator from the beginning using std::begin() and call std::advance() to advance how ever many places you want, so something like:
std::vector<Object> objects;
const size_t n = 20;
auto erase_iter = std::advance(std::begin(objects), n);
objects.erase(erase_iter);
If you want to find the index of an item in a vector then use std::find to get the iterator and call std::distance from the beginning.
So something like:
Object object_to_find;
std::vector<Object> objects;
auto object_iter = std::find(std::begin(objects), std::end(objects), object_to_find);
const size_t n = std::distance(std::begin(objects), object_iter);
This does mean that you need to implement an equality operator for your object. Or you could try something like:
auto object_iter = std::find(std::begin(objects), std::end(objects),
[&object_to_find](const Object& object) -> bool { return &object_to_find == &object; });
Although for this to work the object_to_find needs to be the one from the actual list as it is just comparing addresses.
Consider the following class member:
std::vector<sim_mob::Lane *> IncomingLanes_;
the above container shall store the pointer to some if my Lane objects. I don't want the subroutins using this variable as argument, to be able to modify Lane objects.
At the same time, I don't know where to put 'const' keyword that does not stop me from populating the container.
could you please help me with this?
thank you and regards
vahid
Edit:
Based on the answers i got so far(Many Thanks to them all) Suppose this sample:
#include <vector>
#include<iostream>
using namespace std;
class Lane
{
private:
int a;
public:
Lane(int h):a(h){}
void setA(int a_)
{
a=a_;
}
void printLane()
{
std::cout << a << std::endl;
}
};
class B
{
public:
vector< Lane const *> IncomingLanes;
void addLane(Lane *l)
{
IncomingLanes.push_back(l);
}
};
int main()
{
Lane l1(1);
Lane l2(2);
B b;
b.addLane(&l1);
b.addLane(&l2);
b.IncomingLanes.at(1)->printLane();
b.IncomingLanes.at(1)->setA(12);
return 1;
}
What I meant was:
b.IncomingLanes.at(1)->printLane()
should work on IncomingLanes with no problem AND
b.IncomingLanes.at(1)->setA(12)
should not be allowed.(In th above example none of the two mentioned methods work!)
Beside solving the problem, I am loking for good programming practice also. So if you think there is a solution to the above problem but in a bad way, plase let us all know.
Thaks agian
A detour first: Use a smart pointer such shared_ptr and not raw pointers within your container. This would make your life a lot easy down the line.
Typically, what you are looking for is called design-const i.e. functions which do not modify their arguments. This, you achieve, by passing arguments via const-reference. Also, if it is a member function make the function const (i.e. this becomes const within the scope of this function and thus you cannot use this to write to the members).
Without knowing more about your class it would be difficult to advise you to use a container of const-references to lanes. That would make inserting lane objects difficult -- a one-time affair, possible only via initializer lists in the ctor(s).
A few must reads:
The whole of FAQ 18
Sutter on const-correctness
Edit: code sample:
#include <vector>
#include <iostream>
//using namespace std; I'd rather type the 5 characters
// This is almost redundant under the current circumstance
#include <vector>
#include <iostream>
#include <memory>
//using namespace std; I'd rather type the 5 characters
// This is almost redundant under the current circumstance
class Lane
{
private:
int a;
public:
Lane(int h):a(h){}
void setA(int a_) // do you need this?
{
a=a_;
}
void printLane() const // design-const
{
std::cout << a << std::endl;
}
};
class B
{
// be consistent with namespace qualification
std::vector< Lane const * > IncomingLanes; // don't expose impl. details
public:
void addLane(Lane const& l) // who's responsible for freeing `l'?
{
IncomingLanes.push_back(&l); // would change
}
void printLane(size_t index) const
{
#ifdef _DEBUG
IncomingLanes.at( index )->printLane();
#else
IncomingLanes[ index ]->printLane();
#endif
}
};
int main()
{
Lane l1(1);
Lane l2(2);
B b;
b.addLane(l1);
b.addLane(l2);
//b.IncomingLanes.at(1)->printLane(); // this is bad
//b.IncomingLanes.at(1)->setA(12); // this is bad
b.printLane(1);
return 1;
}
Also, as Matthieu M. suggested:
shared ownership is more complicated because it becomes difficult to
tell who really owns the object and when it will be released (and
that's on top of the performance overhead). So unique_ptr should be
the default choice, and shared_ptr a last resort.
Note that unique_ptrs may require you to move them using std::move. I am updating the example to use pointer to const Lane (a simpler interface to get started with).
You can do it this way:
std::vector<const sim_mob::Lane *> IncomingLanes_;
Or this way:
std::vector<sim_mob::Lane const *> IncomingLanes_;
In C/C++, const typename * and typename const * are identical in meaning.
Updated to address updated question:
If really all you need to do is
b.IncomingLanes.at(1)->printLane()
then you just have to declare printLane like this:
void printLane() const // Tell compiler that printLane doesn't change this
{
std::cout << a << std::endl;
}
I suspect that you want the object to be able to modify the elements (i.e., you don't want the elements to truly be const). Instead, you want nonmember functions to only get read-only access to the std::vector (i.e., you want to prohibit changes from outside the object).
As such, I wouldn't put const anywhere on IncomingLanes_. Instead, I would expose IncomingLanes_ as a pair of std::vector<sim_mob::Lane *>::const_iterators (through methods called something like GetIncomingLanesBegin() and GetIncomingLanesEnd()).
you may declare it like:
std::vector<const sim_mob::Lane *> IncomingLanes_;
you will be able to add, or remove item from array, but you want be able to change item see bellow
IncomingLanes_.push_back(someLine); // Ok
IncomingLanes_[0] = someLine; //error
IncomingLanes_[0]->some_meber = someting; //error
IncomingLanes_.erase(IncomingLanes_.end()); //OK
IncomingLanes_[0]->nonConstMethod(); //error
If you don't want other routines to modify IncomingLanes, but you do want to be able to modify it yourself, just use const in the function declarations that you call.
Or if you don't have control over the functions, when they're external, don't give them access to IncomingLanes directly. Make IncomingLanes private and provide a const getter for it.
I don't think what you want is possible without making the pointers stored in the vector const as well.
const std::vector<sim_mob::Lane*> // means the vector is const, not the pointer within it
std::vector<const sim_mob::Lane*> // means no one can modify the data pointed at.
At best, the second version does what you want but you will have this construct throughout your code where ever you do want to modify the data:
const_cast<sim_mob::Lane*>(theVector[i])->non_const_method();
Have you considered a different class hierarchy where sim_mob::Lane's public interface is const and sim_mob::Really_Lane contains the non-const interfaces. Then users of the vector cannot be sure a "Lane" object is "real" without using dynamic_cast?
Before we get to const goodness, you should first use encapsulation.
Do not expose the vector to the external world, and it will become much easier.
A weak (*) encapsulation here is sufficient:
class B {
public:
std::vector<Lane> const& getIncomingLanes() const { return incomingLanes; }
void addLane(Lane l) { incomlingLanes.push_back(l); }
private:
std::vector<Lane> incomingLanes;
};
The above is simplissime, and yet achieves the goal:
clients of the class cannot modify the vector itself
clients of the class cannot modify the vector content (Lane instances)
and of course, the class can access the vector content fully and modify it at will.
Your new main routine becomes:
int main()
{
Lane l1(1);
Lane l2(2);
B b;
b.addLane(l1);
b.addLane(l2);
b.getIncomingLanes().at(1).printLane();
b.getIncomingLanes().at(1).setA(12); // expected-error\
// { passing ‘const Lane’ as ‘this’ argument of
// ‘void Lane::setA(int)’ discards qualifiers }
return 1;
}
(*) This is weak in the sense that even though the attribute itself is not exposed, because we give a reference to it to the external world in practice clients are not really shielded.
Edit: My debugger was lying to me. This is all irrelevant
Howdy all,
I had a peek at Adding element to vector, but it's not helpful for my case.
I'm trying to add an element (custom class LatLng) to another object (Cluster) from a third object (ClusterManager).
When I pass my LatLng to Cluster (last line of ClusterManager.cpp), and jump into Cluster::addLocation, at the end of the function execution gdb says my new LatLng has been added to Cluster, but the moment I jump back into the scope of the highest class, ClusterManager, the new LatLng added to the vector 'locStore' is not present in either runtime or debug.
Any ideas?
DJS.
DE: Xcode 3.2 (Targeted to Debug 10.5)
OS: OSX 10.6
Compiler: GCC 4.2
Arch: x86_64
ClusterManager.cpp (where it's all being called from):
void ClusterManager::assignPointsToNearestCluster()
{
//Iterate through the points.
for (int i = 0; i < locationStore.size(); i++)
{
double closestClusterDistance = 100.1;
// Make sure to chuck the shits if we don't find a cluster.
int closestCluster = -1;
int numClusters = clusterStore.size();
// Iterate through the clusters.
for (int j = 0; j < numClusters; j++) {
double thisDistance = locationStore[i].getDistanceToPoint( *(clusterStore[j].getCentroid()) );
// If there's a closer cluster, make note of it.
if (thisDistance < closestClusterDistance) {
closestClusterDistance = thisDistance;
closestCluster = j;
}
}
// Remember the penultiment closest cluster.
this->clusterStore[closestCluster].addLocation( this->locationStore[i] );
}
}
ClusterManager.h
#include "Cluster.h"
#include "LatLng.h"
#include <vector>
class ClusterManager{
private:
std::vector<Cluster> clusterStore;
std::vector<LatLng> locationStore;
public:
ClusterManager();
void assignPointsToNearestCluster();
void addLocation(int,double,double);
};
Cluster.h:
#include <vector>
#include <string>
#include "LatLng.h"
class Cluster {
private:
std::vector<LatLng> locStore;
LatLng newCentroid;
bool lockCentroid;
int clusterSize;
int clusterID;
public:
Cluster(int,LatLng&);
void addLocation(LatLng&);
LatLng* getCentroid();
};
Cluster.cpp
Cluster::Cluster(int newId, LatLng &startPoint)
{
this->clusterID = newId;
this->newCentroid = startPoint;
};
void Cluster::addLocation(LatLng &newLocation)
{
(this->locStore).push_back( newLocation );
};
LatLng* Cluster::getCentroid()
{
return &newCentroid;
};
The debugger is possibly lying. I've found Xcode has issues has viewing the contents of vectors, try using some asserts to make sure the vector in question is actually being filled.
What does your copy constructor for the class LatLng look like? When you call std::vector::push_back(), a copy of the argument is made before adding it to the vector. The lack of a non-compiler-generated copy constructor may indicate why you are not seeing certain values in the target vector.
Also, you mention that you are getting an out-of-bounds error when iterating the contents of the vector. This suggests that there are fewer elements in the vector than you expected there to be. Consider iterating through the vector using a for-loop, bound by vector.size().
What does the copy constructor of LatLng do? This determines what actually winds up in the vector when you call push_back.
btw it's a bit more efficient to use iterators rather than indices in your vector loops - less operator[] usage, in favour of direct refs to vector members via the iterator.
std::vector::push_back() expects a const reference as input, but you are passing it a non-const reference instead, so the compiler has to create a temporary LatLng object, which is what gets added to the vector instead of your original LatLng object.