std::shared_ptr operator= changes the object, not the pointer value? - c++

In the little program below, I wanted to be able to change the value inside M m by changing the value of s. But apparently I cannot do it. One way that would work would be to change the raw pointer but this is not safe:
#include <iostream>
#include <memory>
class M{
public:
std::shared_ptr<int> t;
};
std::shared_ptr<int> s;
int main() {
M m;
m.t = s;
s = std::make_shared<int>(5);
std::cout << m.t << std::endl; //prints 0
}
On this little program, I thought that by doing s = std::make_shared<int>(5), s's internal pointer would point to 5. However, what it does instead is substitute the value of s by another value, so m.t is not pointing to the new s.
Isn't it possible to do what I want?

Related

make change after vector::at returns a reference

#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> nums {0,1,2};
vector<int> copy {0};
copy.at(0) = nums.at(0); // nums.at(0) returns a reference
nums.at(0) = -1; // why this line doesn't change copy[0]
std::cout << copy.at(0); // print 0
}
Hi, as code indicates, it looks like changing of nums.at(0) doesn't affect copy.at(0).
Does copy.at(0) = nums.at(0); call the copy-assignment operator a copy?
It doesn't make sense to me this line actually do a copy, because copy.at(0) also returns a reference.
References are bound on initialization. After that the reference refers to the bound object and cannot be made to refer to something else.
Maybe this is best understood by means of an example:
int x = 6;
int& x_ref = x; // bind x_ref to x
int y = 12;
x_ref = y; // assign the value of y to x
In your code copy.at(0) does return a reference, however you cannot rebind that reference to something else. Instead copy.at(0) = something; will assign something to what copy.at(0) references.
I fully agree to above the comments, you have misunderstood.
Also references must be initialized at the time of declaration,
This can possible illustrate your case.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> nums {0,1,2};
int& copy = nums.at(0);
nums.at(0) = -1;
std::cout <<"copy is"<< copy; // print -1
}
Be warned: this is asking for trouble, as soon as the vector reallocates or element is deleted, the reference will be dangling.
See also The concept of references in C++
Online demo

Why does list.end() not change when new item is added?

I am working on a programm which has two lists. One of the list stores objects. The other list stores pointers to items of the list containing the objects. When a new item is added to the object list I want to get the pointer to the object. But I always get the same pointer returned.
Since my program is to big now I made a new, smaller one to show you the problem:
#include <iostream>
#include <list>
using namespace std;
class C_Test
{
public:
int a;
};
int main()
{
std::list<class C_Test> Testlist;
C_Test A;
C_Test B;
Testlist.push_back(A);
C_Test * p = &*Testlist.end();
cout << p << endl;
Testlist.push_back(B);
p = &*Testlist.end();
cout << p;
}
Result:
0x22fe20
0x22fe20
I would expect the programm to print out two different pointers since the end of list should have changed? Why does it give me two times the same pointer?
I really would appreciate your help in this matter.
For starters dereferencing the iterator returned by the member function end has undefined behavior.
I think you mean
C_Test * p = &Testlist.back();

is there a cleaner way to right operator[]() for a vector? [duplicate]

If I define a pointer to an object that defines the [] operator, is there a direct way to access this operator from a pointer?
For example, in the following code I can directly access Vec's member functions (such as empty()) by using the pointer's -> operator, but if I want to access the [] operator I need to first get a reference to the object and then call the operator.
#include <vector>
int main(int argc, char *argv[])
{
std::vector<int> Vec(1,1);
std::vector<int>* VecPtr = &Vec;
if(!VecPtr->empty()) // this is fine
return (*VecPtr)[0]; // is there some sort of ->[] operator I could use?
return 0;
}
I might very well be wrong, but it looks like doing (*VecPtr).empty() is less efficient than doing VecPtr->empty(). Which is why I was looking for an alternative to (*VecPtr)[].
You could do any of the following:
#include <vector>
int main () {
std::vector<int> v(1,1);
std::vector<int>* p = &v;
p->operator[](0);
(*p)[0];
p[0][0];
}
By the way, in the particular case of std::vector, you might also choose: p->at(0), even though it has a slightly different meaning.
return VecPtr->operator[](0);
...will do the trick. But really, the (*VecPtr)[0] form looks nicer, doesn't it?
(*VecPtr)[0] is perfectly OK, but you can use the at function if you want:
VecPtr->at(0);
Keep in mind that this (unlike operator[]) will throw an std::out_of_range exception if the index is not in range.
There's another way, you can use a reference to the object:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {7};
vector<int> *p = &v;
// Reference to the vector
vector<int> &r = *p;
cout << (*p)[0] << '\n'; // Prints 7
cout << r[0] << '\n'; // Prints 7
return 0;
}
This way, r is the same as v and you can substitute all occurrences of (*p) by r.
Caveat: This will only work if you won't modify the pointer (i.e. change which object it points to).
Consider the following:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {7};
vector<int> *p = &v;
// Reference to the vector
vector<int> &r = *p;
cout << (*p)[0] << '\n'; // Prints 7
cout << r[0] << '\n'; // Prints 7
// Caveat: When you change p, r is still the old *p (i.e. v)
vector<int> u = {3};
p = &u; // Doesn't change who r references
//r = u; // Wrong, see below why
cout << (*p)[0] << '\n'; // Prints 3
cout << r[0] << '\n'; // Prints 7
return 0;
}
r = u; is wrong because you can't change references:
This will modify the vector referenced by r (v)
instead of referencing another vector (u).
So, again, this only works if the pointer won't change while still using the reference.
The examples need C++11 only because of vector<int> ... = {...};
You can use it as VecPrt->operator [] ( 0 ), but I'm not sure you'll find it less obscure.
It is worth noting that in C++11 std::vector has a member function 'data' that returns a pointer to the underlying array (both const and non-const versions), allowing you to write the following:
VecPtr->data()[0];
This might be an alternative to
VecPtr->at(0);
which incurs a small runtime overhead, but more importantly it's use implies you aren't checking the index for validity before calling it, which is not true in your particular example.
See std::vector::data for more details.
People are advising you to use ->at(0) because of range checking. But here is my advise (with other point of view):
NEVER use ->at(0)! It is really slower. Would you sacrifice performance just because you are lazy enough to not check range by yourself? If so, you should not be programming in C++.
I think (*VecPtr)[0] is ok.

Pass vector by reference to constructor of class

I have a class called test with which I want to associate a large vector with in the order of million elements. I have tried doing this by passing a pointer to the constructor:
#include <iostream>
#include <vector>
using namespace std;
class test{
public:
vector<double>* oneVector;
test(vector<double>* v){
oneVector = v;
}
int nElem(){return oneVector->size();}
};
int main(){
vector<double> v(1000000);
cout << v.size() << endl;
vector<double>* ptr;
test t(ptr);
cout << t.nElem()<< endl;
return 0;
}
However, this results in a Segmentation Fault:11, precisely when I try to do t.nElem(). What could be the problem?
This is C++, don't work with raw pointers if you don't absolutely need to. If the goal is to take ownership of a std::vector without copying, and you can use C++11, make your constructor accept an r-value reference, and give it sole ownership of the std::vector that you're done populating with std::move, which means only vector's internal pointers get copied around, not the data, avoiding the copy (and leaving the original vector an empty shell):
class test{
public:
vector<double> oneVector;
test(vector<double>&& v):oneVector(std::move(v)){
}
int nElem(){return oneVector.size();}
};
int main(){
vector<double> v(1000000);
cout << v.size() << endl;
test t(std::move(v));
cout << t.nElem()<< endl;
return 0;
}
If you really want a pointer to a vector "somewhere else", make sure to actually assign ptr = &v; in your original code. Or new the vector and manage the lifetime across test and main with std::shared_ptr. Take your pick.
ptr is not initialized. What you "want" to do is:
test t(&v);
However, I think you'd be better suited with references here (it's in the title of your question after all!). Using references avoids unnecessary syntax (like -> over .) which just unnecessarily hinder the reading of the code as written.
class test
{
std::vector<double>& oneVector;
public:
test(vector<double>& v) : oneVector(v) {}
size_t nElem() const { return oneVector.size(); }
};
ptr is an uninitialized pointer. This unpredictable value gets copied to t.oneVector. Dereferencing it is undefined behavior.
You need your pointer to actually point at a valid vector.
You forgot to give your pointer the desired value, namely the address of the vector:
vector<double>* ptr = &v;
// ^^^^^^
In your code, ptr remains uninitialized, and your program has undefined behaviour.

C++ assign dereference pointer object to a variable and use that

Hea everyone!
First of all, I am a completely new to C++ coming from a basic C background so it might be a little weird why I ask this.
The use scenario is that I want to change a map inside a different function by passing the map as a pointer to that function. Because I was reusing someone else's code, it was easier to assign the dereference to a variable instead of changing all of the references. This results in a similar case as this:
using namespace std;
typedef map<long, double> tl_t;
void fillmap(tl_t* m_p) {
tl_t m = *m_p;
m.insert(pair<long, double>(4, 3.0));
}
int main(int argc, char** argv) {
tl_t m;
cout << "Size: " << m.size() << "\n";
fillmap(&m);
cout << "Size: " << m.size() << "\n";
return 0;
}
The funny thing is that now both Size: strings return 0 and the original map m in the main function does not seem to be changed. This, however, works:
using namespace std;
typedef map<long, double> tl_t;
void fillmap(tl_t* m) {
(*m).insert(pair<long, double>(4, 3.0));
}
int main(int argc, char** argv) {
tl_t m;
cout << "Size: " << m.size() << "\n";
fillmap(&m);
cout << "Size: " << m.size() << "\n";
return 0;
}
As far as I can tell, these 2 cases should be working the same as both the reference of m in the main and fillmap function reference the same object. Of course the two m variables reside somewhere differently but should be referencing the same object.
As I am writing this, one thing that might be the problem is that variable m in main IS the map object while the variable m in fillmap TRIES to be the map object but can't because dereferencing the m_p pointer and assigning it to that last m doesn't actually make the last m a reference to the same object but actually copies it. Am I on the right track here?
And yes, I do know in normal use cases you should use a parameter reference in a similar situation, but this bugged the hell out of me :P.
Hopefully someone can enlighten me!
In C++ you have to add & to explicitly say that variable is reference.
In your example:
tl_t& m = *m_p;
should help.
If you use just "tl_t" you create local copy of the object which is destroyed once you leave fillmap function.
Example:
struct X {
int a,b;
}
Now types:
X - place in memory containing both a and b value.
X& - place in memory containing reference (const pointer) to the X.
X* - place in memory containing pointer to the X.
In both X and X& you can access fields of class using dot (xobject.a, xobject.b) but these are not same types.
It is because that
tl_t m = *m_p;
m will be construct by call the copy constructor, the copy process is by value. You just insert the pair<long, double>(4, 3.0) into m, not m_p
However,
(*m).insert(pair<long, double>(4, 3.0))
*m is the object you passed in by pointer, so, the pair<long, double>(4, 3.0) is inserted to *m itself.