class A{
Add(const B&);
vector <B*> vect;
};
A & A::Add(const B& obj){
vect.push_back(&obj);
return *this;
}
here I am getting fpermissive error, because argument of push_back is constant, how do I get rid of this?
I tried to create local copy in Add such as
B tmp;
tmp = obj;
vect.push_back(&tmp);
but I am not sure about this, as program step out of this method Add, tmp gets destructed, and adress in vector will point to invalid place in memory?
Your problem arises from API inconsistency. 2 options here:
Drop the const from the signature of Add: Add(B&)
Store const B* pointers in the vector: vector<const B*> vect;
The first option will allow to modify the contents of your objects while the second one will forbid it. The choice depends on your program logic.
Your problem is that if you provide a const reference as the function parameter of Add you are telling the compiler that whatever you are passing is never going to be changed as an effect of that function.
On the other hand you try to store a non-const pointer in the vector which means that the users of that vector are allowed to change the value correlated to that pointer.
To get rid of the error you have to decide what is the type of behaviour you actually want from your program:
if you want to store read-only references to your "B" objects then you have to store them as const pointer in the vector. If you want the users of that vector to be able to use non-const functions of B, that is to change B, you have to pass it to the Add function as non-const reference.
Related
I have a vector as a member of a class "B". It has its set and get functions:
setVector(vector<A*>)
getVector()
I am interested in filling this vector from another function that uses an object of this class "B".
So I created new objects of class "A" and I did the following to update the vector member variable of the class "B" by mistake:
A* obj = new A;
B b;
B.getVector().push_back(obj);
What happened is that push_back did not work. In other words when I try to see the member variable using a debugger I see that the vector member variable still has a capacity of 0 as if I did not push_back anything to it.
I tried changing my implementation to be:
vector<A*> tempVector;
B b;
A* obj = new A;
tempVector.push_back(obj);
b.setVector(tempVector);
And it worked as expected.
I wanted to understand why that first behavior was a mistake? As I understand the constructor of class B should create a vector by default. So when I use the getVector() function it should return that created vector to me and then I can push_back to it. So I wanted to know what did I get wrong in this situation?
The problem is probably the return type of getVector(). Assuming it is defined as vector<A*> getVector(), it returns the vector by value, which means that you did the push_back on a copy of the vector, but not on the actual vector member.
If you want to be able to modify the vector from outside the class, all you have to do is change the function signature to pass it by reference instead: vector<A*>& getVector(). This will make sure the modifications (such as push_back) happen on the member variable.
The signature of getVector() is probably something like std::vector<A*> getVector(). This will return a copy of the actual vector. Then you push_back to the copied vector, but never modify the member variable. You want to return a reference:
std::vector<A*> &getVector();
const std::vector<A*> &getVector() const;
I'm trying to return an std::vector that is inside a map but I don't seem to get it right.
The code below is what I have tried and the one further below is the test it's supposed to pass
namespace grade_school {
class school {
public:
inline std::map<int, std::vector<std::string>> roster () {return
MySchool;}
void add (std::string studentname , int grd);
std::vector<std::string>& grade (int grd);
private:
std::map<int,std::vector<std::string>> MySchool;
};
}
void grade_school::school::add (std::string studentname, int grd){
MySchool[grd].push_back(studentname);
}
std::vector<std::string>& grade (int grd) {
return MySchool[grd];
};
TEST_CASE("grade_returns_the_students_in_that_grade_in_alphabetical_order")
{
grade_school::school school_;
school_.add("Franklin", 5);
school_.add("Bradley", 5);
school_.add("Jeff", 1);
const auto actual = school_.grade(5);
const vector<string> expected{"Bradley", "Franklin"};
REQUIRE(expected == actual);
}
I expected that the return type would be the vector contained inside the map but the compiler error i got was error C2065: 'MySchool': undeclared identifier
I expected that the return type would be the vector contained inside the map.
This leaves room for interpretation, depending on how you interpret this sentence, this already is the case – or not...
std::vector<std::string> grade(int grd);
In C++, we speak of returning 'by value'. You get exactly the values that are in the map. But returning by value means, you get a copy of. If you now modify the returned value, you actually modify the copy, but not the vector in the map.
std::vector<std::string>& grade(int grd);
// ^ note the ampersand!
The ampersand denotes that we just return a reference to the vector in the map (in this case, it behaves similar to a pointer), and via the reference, you now can modify the vector in the map directly:
grade(7).push_back("seven");
For completeness: pointer:
std::vector<std::string>* grade(int grd) { return &mySchool[grd]; }
// need address-of operator: ^
grade(7)->push_back("seven");
Usually, one prefers the reference, but the pointer can be useful in some specific scenarios, e. g. you can return a nullptr (not possible with references) to denote that there is no suitable vector for some specific input.
In some use-cases, you might not want to allow to modify the vector returned. Returning by copy avoids that, but a copy might be expensive. To avoid copies and still disallow modifications, you can return by const reference:
std::vector<std::string> const& grade(int grd);
Admitted, a user might const_cast the const away, but then it's the user breaking a contract (returning something as const means tealling: 'Don't modify it, if you do so, your fault!').
Use reference type for return value:
std::map<int,std::vector<std::string>> MySchool;
std::vector<std::string>& grade (int grd) {
return MySchool[grd];
}
Using reference with containers and other enough big data objects is preferable due to perfomance. This minimize memory operations caused by data duplications.
Non const reference approach is good if you plan to modify vector outside of method or object which incapsulate this map. This is simple solution which always give you actual data and allow to modify.
Better approach is to incapsulate modifications of data in methods of class (or api function set) to avoid unexpected and unverified modificaions by user. Use return type const reference for that like this:
const std::vector<std::string>& grade (int grd)
If you really need to have a copy of array for that case you can do this simple by expression sintax. For example assign to value instead of reference:
// ref - is const reference to some array returned by function
const std::vector<std::string>& ref = grade(10)
// array - is a full copy of array pointed by reference returned from function
std::vector<std::string> array = grade(10)
When you return reference to container or some data you need to understand problem that user code save reference and it may be used multiple times. And during that time and dependent from how your container or your code manage data in memory it may bring to problem. So it is possible case when data at memory referenced by prevously returned reference is released. Returned before reference become refer to wrong memory. But user code may use that reference and bring to access violation or some undefined behaviour.
Even if your object guarantee that reference returned by method will exists during all object life time. Reference may be saved in the user code more long time than object itself. So there is no guarantee at all.
However we may use simple rule just to not save a reference in variable. Just use data in same expression with function call always:
grade(10).length()
std::accumulate(grade(10).begin(), grade(10).end(), 0)
However user may do not know or forget this rule.
And of course your function must always return reference to existing data. For example if no such array at specified index you need to create appropriate array at specified index and use it for return.
And of course function must not return reference to any non-static variable declared in function body because all of them will be destroyed after function return and before return value will be used. Which guarantee crash of aplication. Use return by value for that case.
I am trying to temporary store a vector of unique pointers and switch them between 2 objects. Here I try to move the ownership of the vector to a temporary vector named oldcards.
std::vector<std::unique_ptr<Building>> oldCards = std::move(player.getBuildingCards());
player.setBuildingCards(std::move(otherPlayer.getBuildingCards()));
otherPlayer.setBuildingCards(std::move(oldCards));
Player.cpp
std::vector<std::unique_ptr<Building>> const& Player::getBuildingCards() const
{
return this->buildingCards;
}
void Player::setBuildingCards(std::vector<std::unique_ptr<Building>> buildingCards)
{
this->buildingCards = std::move(buildingCards);
}
Player.h
std::vector<std::unique_ptr<Building>> buildingCards;
To conclude: I want to swap 2 vectors, I want player to have the ownership of the vector of otherPlayer and vice versa. However, I get the: attempting to reference a deleted function error. How can I achieve this?
I am trying to temporary store a vector of unique pointers and switch them between 2 objects.
Why? Using std::vector::swap would accomplish the same thing with less effort. (Note that this swap most likely should occur within a member function, so there would be no need to use the public accessor functions.)
std::vector<std::unique_ptr<Building>>const& Player::getBuildingCards() const
This returns a const reference. You are not allowed to change something marked const. Moving data out of something counts as changing that something, so moving from getBuildingCards() is not allowed.
void Player::setBuildingCards(std::vector<std::unique_ptr<Building>> buildingCards)
This function takes a copy of a vector as a parameter. Since a vector of unique_ptr cannot be copied, this function signature is DOA. (For the intended purpose, you would want the type of the parameter to be std::vector<std::unique_ptr<Building>>&& to indicate that you will be moving from the parameter.)
You cannot move from cons T& so copy constructor of oldCards is called which is of course deleted. player.getBuildingCards() cannot change the player instance anyway because you marked it as const.
Cleanest solution (at least according to me) would to implement swapBuildingCards friend function:
class Player
{
//...
std::vector<std::unique_ptr<Building>> buildingCards;
friend static void swapBuildingCards(Player& p1, Player &p2)
{
using std::swap;
swap(p1.buildingCards,p2.buildingCards);
}
};
I have a vector of pointers to an object:
vector<Foo*> bar;
In a method, I am given an Foo object and need to add it to the vector. This is my current attempt:
void push(const Foo &a){
bar.insert(bar.begin(), a);
}
I know this doesnt work because a was passed as a reference, but I can't seem to get the pointer for a to add to bar.
How can I add a to the vector bar?
You can't put an object in a container of pointers.
If you want to put an object in, then you'll need a container of objects:
vector<Foo> bar;
In that case, all the objects must be of the same type; if Foo is actually a base class, and you want to store a variety of different derived types, then you'll need to store pointers.
If you want a container of pointers, then you'll need to put a pointer in it:
bar.insert(bar.begin(), &a);
In that case, you need to take care with the object's lifetime, and make sure you don't use the pointer after the object is destroyed. Smart pointers might be helpful.
Add the address of a. Pointers store addresses, which is how they point to something.
bar.insert(bar.begin(), &a);
I'm presuming you have a good reason for using pointers, but make sure the a being passed in isn't temporary and that the object you pass in outlives the vector so that you don't end up with a dangling pointer.
Correct me if I am wrong, but a is not a pointer in that code, even though it is passed by reference. You should be able to use & on it to gets it's address, correct?
Just take the address of a. The reference really is just that, a reference, so taking the address of it actually yields the address of what it refers to.
void push(const Foo& a)
{
bar.insert(bar.begin(), &(a));
}
Coming from C#, where class instances are passed by reference (that is, a copy of the reference is passed when you call a function, instead of a copy of the value), I'd like to know how this works in C++. In the following case, _poly = poly, is it copying the value of poly to _poly, or what?
#include <vector>
using namespace std;
class polynomial {
vector<int> _poly;
public:
void Set(vector<int> poly);
};
void polynomial::Set(vector<int> poly) {
_poly = poly; <----------------
}
poly's values will be copied into _poly -- but you will have made an extra copy in the process. A better way to do it is to pass by const reference:
void polynomial::Set(const vector<int>& poly) {
_poly = poly;
}
EDIT I mentioned in comments about copy-and-swap. Another way to implement what you want is
void polynomial::Set(vector<int> poly) {
_poly.swap(poly);
}
This gives you the additional benefit of having the strong exception guarantee instead of the basic guarantee. In some cases the code might be faster, too, but I see this as more of a bonus. The only thing is that this code might be called "harder to read", since one has to realize that there's an implicit copy.
This will do a shallow-copy of the vector of ints. This will generally work as you would expect (_poly will end up containing the same values as poly).
You would see some strange behaivor if you had pointers (as they would be copied by value).
In general, you would want to pass that parameter by const reference:
void polynomial::Set( const vector<int>& poly )
In this case, passing by const reference will not affect the outcome and will be more efficient since it will eliminate an unneeded copy of the vector being passed into the method.
This will copy the entire vector. Assignment is by value in C++. If you are assigning a pointer, the pointer value is assigned. References may not be reassigned to refer to another object once initialized, so assignment of them alters the referent object.
The copy operator for vectors will copy the contents of the vector over.
There are three possibilities:
Pass by value
void someFunction(SomeClass theObject);
Pass a pointer
void someFunction(SomeClass *theObject);
Pass by reference
void someFunction(SomeClass &theObject);
Your vector will be copied.
What's actually going on is that the "=" operator of vector has been overloaded to do the actual copy.
Yes, the line you point to is copying the entire vector. Furthermore, there will be a copy on the function call, as well, since that's not const.
Basically, if the vector has any size to it, this is VERY expensive.
Unless you assign or pass a parameter by reference (using the & prefix) you are passing by value. For classes, this means that a copy of the object is constructed using either a supplied or implicitly generated (shallow) copy constructor for the type. This can be expensive - and is often undesirable.
In your example, the vector is copied twice - once when it is passed as a parameter to the Set() method, and again when it is assigned to the _poly member.
You could avoid the first copy by passing the vector by reference:
void polynomial::Set(const vector<int>& poly) // passes the original parameter by reference
{
_poly = poly; // still makes a copy
}