I am not sure how to exactly express my thoughts and hence my googling is failing but is there a way to create const objects from non-const objects?
For instance, my graph class is as follows:
class graph
{
public:
graph( int n )
{
adj_list.resize( n );
adj_mat_wgt.resize( n, std::vector<double>( n ,100.0 ) );
_n = n;
};
~graph() {};
void add_arc( int u, int v, double wit );
std::vector<int> get_shortest_path( int source, int sink );
void set_const_gs_weights();
private:
std::vector<std::vector<int>> adj_list;
std::vector<std::vector<double>> adj_mat_wgt;
int _n;
};
}
I want to create another private variable and use set_const_gs_weights to create a copy of adj_mat_wgt but has some constness such that it can never be changed. The reason for this is that I will be modifying adj_mat_wgt though some functions and I need to go back to the original adj_mat_wgt by taking a non-const copy of the const object that I would like to create.
I understand that I can always just create another non-const variable like adj_mat_wgt_cpy and store a copy of adj_mat_wgt in it and never touch it except for using it to create another fresh copy for adj_mat_wgt after my changes. But is there a way to make adj_mat_wgt_cpy const? Any help is appreciated.
Related
This is in relation to an earlier question I had. I haven't managed to solve the problem there but for now I'm just trying to get better acquainted with the code to figure out how to deal with that problem.
Towards that goal, I've got around to trying out the suggestions given in that question and I'm a little stumped as to why the following isn't working.
in the header I have
class A {
public:
typedef std::multimap<int, double> intdoublemap_t;
const intdoublemap_t& getMap() const;
void setkey(int k);
void setvalue(double v);
void insertIntoMap();
intdoublemap_t mMapA;
private:
int key;
double value;
};
class B {
public:
typedef std::multimap<int, double> intdoublemap_t;
void mapValues(const A& a);
private:
intdoublemap_t mMapB;
};
in the implementation I have
const A::intdoublemap_t& A::getMap() const { return mMapA; }
void A::setkey(int k) { key = k; }
void A::setvalue(double v) { value = v; }
void A::insertIntoMap(){mMapA.insert(std::make_pair(key, value));}
void B::mapValues(const A & a){ const A::intdoublemap_t& mref = a.getMap();
mMapB = mref; }
and in main()
A a;
a.setkey(10);
a.setvalue(1232.2);
a.insertIntoMap();
B b;
b.mapValues(a);
The code compiles fine and everything to do with a works as expected but the map is not passing to b at all. It stays empty
Can anyone tell me why?
edit: I took another look at this and saw how to do it. I knew it was something stupidly basic. I just had to set mref in the function to a map in B and then could call a function to work on that map within B.
As #FrancoisAndrieux notes, your getMap() only sets a reference local to the function - not the class' intdoublemap_t mref. If you want the latter to be a reference to a map elsewhere, you have three options:
Make it intdoublemap_t& mref, initialize it on construction of the B instance.
Make it std::reference_wrapper<intdoublemap_t> mref, set it whenever you want (e.g. in mapValues().
Make it intdoublemap_t* (or std::shared_ptr<intdoublemap_t> in both A and B), set it whenever you like.
Note: As #FrancoisAndrieux says in a comment, with the second and third option (and without std::shared_ptr) you will have to be careful not to allow the reference to be used after the original object's lifetime has expired.
Having said all the above - I must also say that your design seems rather off to me. You should really not be doing any of these things and I'm 99% sure you're approaching your task the wrong way.
By other purpose, I mean Clone. Here is a simplified example: I have objects, some are squares, some are boxes, which are both Object2D. Each one has a unique id.
In this system, I don't need a typical meaning of copy of an object. A typical copy constructor is used when object is passed by value, returned by value, and ... Here in this system every object is unique, so we don't need the typical copy constructor. Two squares will differ for at least the id. Therefore, I am using the copy constructor to make clones. During a clone, I will deep copy the tree structure except the id.
#include <iostream>
#include <string>
#include <memory>
#include <cstdlib>
#include <vector>
int offset(){
return rand()%100-50;
}
int location(){
return rand()%10000-5000;
}
class Object2D{
public:
int x_, y_;
int id;
static int count;
Object2D(int x, int y):x_(x), y_(y){
id=count++;
}
};
int Object2D::count=0;
class Square: public Object2D{
public:
int getParent(){return containedBy_->id;}
Square(Object2D* containedBy, int size):
Object2D(containedBy->x_+offset(), containedBy->y_+offset()),
containedBy_(containedBy),size_(size){
std::cout<<"Square constructor"<<std::endl;
}
Square(const Square& other):
Object2D(other.x_-other.containedBy_->x_, other.y_-other.containedBy_->y_),
containedBy_(other.containedBy_), size_(other.size_){
std::cout<<"Square clone"<<std::endl;
}
private:
Object2D* containedBy_;
size_t size_;
};
class Box:public Object2D{
private:
size_t l_;size_t h_;
std::vector<std::shared_ptr<Square>> all;
public:
void addSquare(int size){
auto temp = std::make_shared<Square>(this, size);
all.push_back(std::move(temp));
}
const std::vector<std::shared_ptr<Square>>& getAll() const{
return all;
}
Box(int x, int y, size_t l, size_t h):
Object2D(x,y), l_(l), h_(h){}
Box(const Box& other):Object2D(location(), location()){// clone the other box, put cloned squares in
for(const auto& item:other.getAll()){
all.push_back(std::make_shared<Square>(*item));
}
}
void showOffsets(){
std::cout<<"show offsets of all components for container"<<id<<":";
for(const auto& item: all){
std::cout<<item->id<<"("<<item->x_-x_<<","<<item->y_-y_<<")"<<" ";
}
std::cout<<std::endl;
}
};
int main()
{
Box b(100,100,100,100);
std::cout<<"before do it"<<std::endl;
b.addSquare(10);
Box c(b);
std::cout<<b.id<<c.id<<std::endl;
b.showOffsets();
c.showOffsets();
return 0;
}
Here I clone a box, I need to also clone the contained squares, and keep their offsets. The cloned objects will have new ids, which are all unique.
Question
Is it a good idea to use copy constructor for clone? Note that, in this case, the copy constructor will behave differently from a typical copy constructor, so I need to forbid any way to make a call to the typically expected copy constructor, such as I can't use vector to contain squares, since a simple vector erase will call copy constructor which will not preserve the id. So I used smart pointers.
Second, how come the offsets are not copied during clone? That is the thing I would like to preserve.
Results:
before do it
Square constructor
Square clone
02
show offsets of all components for container0:1(36,33)
show offsets of all components for container2:3(-1879,2256)
yes, you can define your own copy constructor.
however, as you already noted, this way you'll find it hard to "forbid" copies where you do not want them explicitly.
my suggestion: give your object a clone() function and delete the copy constructor (maybe also the copy operator).
this way you only clone when you explicitly intend to.
I want to define an array of structs, but this is not working because it has a const field without default constructor.
Struct is part of an SDK and looks like following:
struct SParametricParamDef
{
const TXString fUniversalName;
SResString fLocalizedName;
const TXString fDefaultImperial;
const TXString fDefaultMetric;
EFieldStyle fFieldStyle;
short fChoicesChcID;
};
TXString does not have a default constructor. So following is failing:
SParametricParamDef *arrParams = new SParametricParamDef[size]; // <= throws compile time exception
for (int i = 0; i < size; i++)
{
arrParams[i] = params[i].def; // <= also throws an exception, because operator = is not available
}
Is there some way to solve this? I need an SParametricParamDef* as a result, because this array is used in the SDK again...
Info
In an old SDK version, const TXSTring was const char* and back then I did not have problems... Now I need to adjust my code to work with the new structures...
The error you get is not primarily about operator = but about the fact that you default-constructed an object with const members. This will render them immutable and any attempt to modify them, as you are trying in the loop, must fail.
Fortunately, you can use emplace_back to initialize the SParametricParamDef objects right inside the vector without taking the indirection of default-construction and assignment:
std::vector<SParametricParamDef> arrParams;
for(std::size_t n = 0; n < size; ++n) {
arrParams.emplace_back(params[n].def);
}
This should minimize the amount of copying and comes without the need to modify the struct definition.
The compiler is telling you that you are asking for a TXString to be created without directing how it can be initialised. It is difficult to know how to address the problem of creating a TXString object since you haven't given a list of the constructors for the class, but as it stands a change would need to be made to the code you've given. Some ways of solving this are as follows:
The most obvious is to add a default constructor for SParametricParamDef which initialises the TXString objects:
struct SParametricParamDef
{
SParametricParamDef() : fUniversalName(...), ... {}
...
Another approach, given that the variables are const might be to make them const static
Say, for simplicity's sake, that the TXString object was as follows:
struct TXString{
TXString(char a) : _a(a) {}
char _a;
};
You could then change your declaration of SParametricParamDef to:
struct SParametricParamDef
{
const static TXString fUniversalName;
...
and then define fUniversalName in your implementation file as follows:
const TXString SParametricParamDef::fUniversalName('D');
Another way might be to wrap a TXString object in another object that does have a default constructor:
struct TXStringWrapper {
TXStringWrapper() : _s(...) {} // [1]
const TXString& get() { return _s; }
private:
TXString _s;
}
At [1], you create the TXString in whatever specific, non-default way that you care.
That looks like an example for using a placement new:
SParametricParamDef *arrParams = (SParametricParamDef *) new char[size * sizeof(*arrParams)];
for (int i = 0; i < size; i++)
{
// constructs an object in a pre-allocated memory
new(arrParams+1) SParametricParamDef(params[i].def);
}
You should explicitely call a destructor if it is not trivial before freeing the array:
for (int i = 0; i < size; i++)
{
~SParametricParamDef(arrParams+1);
}
delete[] ((char *) arrParams);
This is rather old fashioned because it mimics the initialization of structs in C, but it is the only way I know to build an array of objects that only have non trivial constructors (AFAIK, the std::vector way requires copyable or movable objects)
When using arrays you can do something like
class SomeClass
{
public:
int* LockMember( size_t& numInts );
private:
int* member;
size_t numInts;
};
int* SomeClass::LockMember( size_t& out_numInts )
{
out_numInts = numInts - 1;
return member + 1;
}
To return an array offset by some amount so as to prevent someone from modifying some part of contingeous memory, or, atleast, show some intent that this part of contingeous memory of the object should remain untouched.
Since I use vectors everywhere, I am wondering if there was some way to accomplish the same sort of thing:
class SomeClass
{
public:
std::vector<int> LockMember( void );
private:
std::vector<int> member;
};
std::vector<int> SomeClass::LockMember( void )
{
// somehow make a vector with its beginning iterator pointing to member.begin() + 1
// have a size smaller by one, still the same end iterator. The vector must be
// pointing to the same data as in this class as it needs to be modifiable.
return magicOffsetVector;
}
With the commented part replaced by real code. Any ideas?
If I understand you correctly: You want some memory with two parts: At the beginning you want something that can't be touched, and after that you want something that is open for use by client code.
You could do something along the following code. This will give the client code a copy to play with. This does mean you would have to do a lot of copying, though.
class SomeClass
{
public:
std::vector<int> getMember( void ) const;
void setMember(std::vector<int> newContent);
private:
std::vector<int> member;
size_t magicOffset;
};
// Read restricted part
std::vector<int> SomeClass::getMember( void ) const
{
return vector<int>(member.begin() + magicOffset, member.end());
}
// Assign to restricted part
void SomeClass::setMember(const std::vector<int>& v)
{
std::copy(v.begin(), v.end(), member.begin() + magicOffset);
}
In order to avoid the copying, it is possible that you could allocate memory for two vectors, one for the protected part and one for the unprotected part, and use placement new to put both vectors into that memory, thus ensuring that they are in contiguous memory. And then give the client code more or less free access to the public part of the vector. However, there's still the thing with bookkeeping variables in vector, and basically this would be an awful hack that's just waiting to blow up.
However, if you only need access to the unrestricted part on a per-element basis, you could just do range-checking on the arguments, i.e.:
int getElement(size_t idx)
{
idx += magicOffset;
if (idx > member.size() || idx < 0) throw std::out_of_range("Illegal index");
return member[idx];
}
And then either provide a setElement, or return int&.
I have a vector< vector< vector< int>>> and I would like to extract from it a vector< vector< int>> to process it individually.
The problem is that when I write :
myMatrix = myCube[anIndex];
the matrix is copied but I only want a reference in order to save memory.
Can you please help me out ?
Thanks a lot!
Just use
vector<vector<int> >& myMatrix = myCube[anIndex];
Use an Iterator of type vector< vector< int> >::const_iterator. Hope this helps.
vector::operator[] returns a reference - as long as you store that result into a reference instead of a full-blown object you should avoid a copy.
vector< vector<int > >& myMatrix = myCube[anIndex];
If myMatrix is a class member and you want to be able to initialise it outside the constructor, your only choice is using a pointer:
class Whatever
{
//...
vector<vector<int>>* myMatrix;
//...
}
myMatrix = &myCube[anIndex]
EDIT: If you can live with initialising myMatrix in the constructor, you can use a reference:
class Whatever
{
//...
vector<vector<int> >& myMatrix;
//...
}
Whatever::Whatever(vector<vector<vector<int> > >& myCube), int anIndex)
: myMatrix(myCube[anIndex])
{
//...
}
Incidentally, you have to separate the > in your code, unless you are using a C++0x conformant compiler; otherwise, the compiler will parse the >> as operator>> and give you an error.
Instead of using operator[] use functions returning iterators as advance, and declare the matrix as follows
vector< vector< int> >::iterator myMatrixPtr;
myMatrixPtr = std::advance(myCube, anIndex);
Now you are able to work with myMatrixPtr as if it were a pointer. If you prefer a reference you can initialize one after this initialization
vector< vector<int > >& myMatrix = *myMatrixPtr;
Be careful with member references! If the referred-to object is cleaned up before the instance of MyClass is, you will have an invalid reference. Often (but not always), if you find that you need to use a member reference, it is an early warning sign that your design could be improved. I rarely use member references for anything other than as a handle to an object's owner, where I can be absolutely certain that the referred-to object will outlive the reference.
It might help if you change slightly your class' responsibilities. Right now, you are building up a set of data, and then creating an object to which you pass that set of data. Instead, why not first build the object, then put the data directly into it.
// To start, define your class to allow you to build up the data
class MyMatrix
{
public:
MyMatrix ()
{ }
void setData (int x, int y, int data)
{ this->myData [x][y] = data; }
int getData (int x, int y)
{ return this->myData [x][y]; }
private:
vector<vector<int> > myData;
}
// Then, create a vector of 6 (or however many you need) matrices
int numberOfMatrices = 6;
vector<MyMatrix> myCube (numberOfMatrices);
// Then, fill in the vector
for (int matrixIndex = 0; matrixIndex < numberOfMatrices; matrixIndex++)
{
// Fill in the data for this matrix
MyMatrix ¤tMatrix = myCube [matrixIndex];
currentMatrix.setData (0 /* x */, 0 /* y */, 0 /* data */);
// ... rest of data
}
Then, you have all the data already in your objects, ready to be processed as you need. Plus, each object owns its data, so as long as the object is around, its member data will be valid. Best of all, using objects with usefully named member functions will make your code much more self-documenting than tons of nested containers.