C++ why raw pointer won't increase reference count of shared_ptr? - c++

the shared_ptr use reference count to determine when to destroy the object.
And pls look at this code:
int main() {
std::shared_ptr<int> pt = std::make_shared<int>(3);
int *pt2 = pt.get();
cout << "reference count " << pt.use_count() << endl;
pt = 0;
cout << *pt2;
};
after I set pt to 0, the reference count should become 0, and the object should be destroyed. But I can still use pt2 to access it. In my case, the result is correct, but I guess it's just luck. So does it mean that the reference count mechanism still can not make it 100% safe if the programmer want to do some stupid thing?

after I set pt to 0, the reference count should become 0, and the object should be destroyed
The reference count did become zero and the object was destroyed.
Replace int with your own class MyInt to see the constructors and destructors being called...
class MyInt
{
private:
int val;
public:
MyInt() : val(0) { std::cout << "default c'tor called" << std::endl; }
MyInt(int rhs) : val(rhs) { std::cout << "c'tor (" << rhs << ") called" << std::endl; }
~MyInt() { std::cout << "d'tor called" << std::endl; }
int getval (void) { return val; }
};
… then update main() …
int main()
{
std::shared_ptr<MyInt> pt = std::make_shared<MyInt>(3);
MyInt* pt2 = pt.get();
std::cout << "reference count " << pt.use_count() << std::endl;
pt = 0;
std::cout << pt2->getval() << std::endl;
return 0;
}
The output will (perhaps) look like this...
c'tor (3) called
reference count 1
d'tor called
3
runnable sample
The fact that the last line of output is the value three (if it is three) is not evidence that the object was not deleted.
Dereferencing a pointer that points to a deleted object is undefined behaviour so anything can happen.

That is not how shared_ptr works.
The count increments when you generate a new shared pointer from the first one. get is just a method to deal with legacy code that can only take a raw pointer.
By using get you are subverting the safety of the smart pointer.
In other words, a pointer from get is only good as an observer, not as an owner and for when you really need a raw pointer.
If you just need an observer use weak_ptr.
It is true that in principle get could increment the count assuming ownership, but still it wouldn't be clear when to decrement it again.
Once the raw pointer is extracted there is no way to get back to the counter of the original.
Stay away from using get unless you know what you are doing.
This is how it works:
#include<iostream>
#include<memory>
using std::cout; using std::endl;
int main(){
std::shared_ptr<int> pt = std::make_shared<int>(3);
assert(pt.use_count() == 1);
std::shared_ptr<int> pt2 = pt;
assert(pt.use_count() == 2);
assert(pt2.use_count() == 2);
pt.reset(); // or pt = 0;
assert(pt.use_count() == 0);
assert(pt2.use_count() == 1);
assert(*pt2 == 3);
assert(!pt);
return 0;
}

Related

Questions about the ownership transfer of unique_ptr

For the following code:
#include <memory>
#include <iostream>
#include <vector>
using namespace std;
struct pm
{
pm() : a(make_unique<vector<int>>(1, 10)){};
unique_ptr<vector<int>> a;
};
struct parms
{
parms() : a(make_unique<pm>()){};
unique_ptr<pm> a;
};
class test
{
public:
test() : p(make_unique<parms>()) {}
unique_ptr<const parms> getParms()
{
return move(p);
}
void setParms(int b)
{
p->a->a->push_back(b);
}
void pp()
{
cout << p->a->a->at(0) << "\n";
}
private:
unique_ptr<parms> p;
};
int main()
{
auto t = make_unique<test>();
t->pp();
cout << t->getParms()->a->a->at(0) << "\n";
cout << (t->getParms()==nullptr) << "\n"; ;
}
t->getParms() is a nullptr after we "cout << t->getParms()->a->a->at(0) << "\n";".
If we do the same thing for the ptr,
int main()
{
auto t = make_unique<test>();
t->setParms(5);
t->pp();
auto ptr = t->getParms();
cout << ptr->a->a->at(0) << "\n";
cout << (ptr==nullptr) << "\n"; ;
}
ptr is not a nullptr.
My question is: why cout t->getParms(), then t->getParms() is a nullptr but prt is not? Is it because of the life scope of unique_ptr? Or the temporary rvalue? What's the reason behind this behavior?
Your method getParams() transfers ownership to the caller.
unique_ptr<const parms> getParms()
{
return move(p);
}
Member is moved to the return value and now the caller owns the pointee. You are not storing the returned value here:
cout << t->getParms()->a->a->at(0) << "\n";
Though, even if you did, t does not own the param anymore, hence when you ask t again:
cout << (t->getParms()==nullptr) << "\n"; ;
It doesnt know about the param anymore.
In the second example you transfer ownership from t to ptr:
auto ptr = t->getParms();
Now ptr owns the param. And you can inspect the pointer or the value as often as you like:
cout << ptr->a->a->at(0) << "\n";
cout << (ptr==nullptr) << "\n"; ;
There is no transfer of ownership in those two lines.
What's the reason behind this behavior?
The reason, as stated above, is that getParams() transfers ownership to the caller. Thats rather uncommon for a getter method. Perhaps "stealer-method" would be a better name ;). If you don't want to give up ownership (and you are certain that the pointer is a valid one) you can simply return a reference:
const parms& getParms() const { return *p; }
My question is: why cout t->getParms(), then t->getParms() is a nullptr but prt is not?
t->getParms() transfers the ownership to the caller. This sets t->p to null. Since t->p no longer owns a pointer, there is nothing to transfer when you call t->getParms() a second time.
You never transferred ownership from ptr, so it hasn't been set to null.

Copy constructor + Shallow & deep copy

I wanted to ask that when I don't write any copy constructor explicitly so the compiler automatically generates the copy constructor which performs shallow copy by default right?
So in the main() program when I changed the values of integers a, b and pointer p only the value of p changed and values of a and b remain unchanged in the copied object. Why the values of a & b didn't change too? My code is:
#include <iostream>
#include <string.h>
using namespace std;
class Dummy {
private:
int a, b;
int *p;
public:
Dummy() {
p = new int;
}
void setData(int x, int y, int z) {
a = x;
b = y;
*p = z;
}
void showData() {
cout << "a = " << a << " b = " << b;
cout << " p = " << *p << endl;
}
~Dummy() {
delete p;
}
};
int main() {
Dummy d1;
d1.setData(3, 4, 5);
Dummy d2 = d1;
d1.showData();
d2.showData();
d1.setData(6, 7, 8);
d1.showData();
d2.showData();
return 0;
}
The output of my program is:
a = 3 b = 4 p = 5
a = 3 b = 4 p = 5
a = 6 b = 7 p = 8
a = 3 b = 4 p = 8
What I'm saying is while the pointer of object d2 changed when I changed the values of object d1 then why didn't the values of a & b of object d2 changed too?
Also I'm using delete keyword in the destructor to delete the dynamically allocated pointer:
~Dummy() {
delete p;
}
But it's crashing my program instead. Why is that?
You've totally got it wrong - The idea of shallow copy. Actually, c++ does not have anything called deep copy built into itself. So, calling something shallow copy is a bit wrong. And just the use of these words shallow copy creates a lot of confusion too.
Now, let me explain, what happens when cpp performs initialization using assignment. cpp or c(while copying struct) has a concept called bitwise copy. In this concept, all the member variables of one object(struct object/class object - you can say either) is identically copied to another object. Now, it's totally wrong idea that, both objects point to same memory location. In actual, both object has their own memory location and of course, their variables occupy different memory spaces. For you, I have write some tests regarding memory. You would understand perfectly, if you just see the test and it's output:
#include <iostream>
#include <string.h>
using namespace std;
class Dummy {
int a, b;
int *p;
public:
Dummy() {
p = new int;
}
void setData(int x, int y, int z) {
a = x;
b = y;
*p = z;
}
void showData() {
cout << "a = " << a << " b = " << b;
cout << " p = " << *p << endl;
cout << endl; // an extra new line for readability of output
}
void showMemory() {
cout << "addr(a) = " << &a << " addr(b) = " << &b;
cout << " addr(p) = " << &p << endl;
}
~Dummy() {
*p = 100;
delete p;
}
};
// testing memory
void memoryTest() {
cout << "testing d1:" << endl;
Dummy d1;
d1.setData(3, 4, 5);
cout << "addr(d1) = " << &d1 << endl;
d1.showMemory();
cout << endl ;
cout << "testing d2:" << endl;
Dummy d2 = d1;
cout << "addr(d2) = " << &d2 << endl;
d2.showMemory();
}
int main() {
// memoryTest
memoryTest();
return 0;
}
And the output of the test was:
testing d1:
addr(d1) = 0x6dfed4
addr(a) = 0x6dfed4 addr(b) = 0x6dfed8 addr(p) = 0x6dfedc
testing d2:
addr(d2) = 0x6dfec8
addr(a) = 0x6dfec8 addr(b) = 0x6dfecc addr(p) = 0x6dfed0
This clearly shows that, the memory occupied by those two objects d1 and d2 are totally different.
Now, you may have another question remain: Then, why, when i write *p=8, it affects both d1 and d2?:
When you assign, Dummy d2 = d1;, we may say something happended like below(though, it's not actually happen when bitwise copy is applied, it's just for clarity):
d2.p = d1.p
So, we know that, d1.p and d2.p contains the same memory location(note: d1.p is a pointer. so, it does not contain any integer, rather it contains memory address of an int).
So, when you write *p = 8, you are telling the program to go to the memory location targeted by p and change the value of that memory location to 8.(note, here, you didn't change the content of d1.p, d1.p still contains the same memory location. rather, you just changed that memory location's content from 5 to 8). That's why when you call d2.p, you get the changed value. cause, d2.p contains the same memory location as d1.p.
Now, there may have one more question: Why your code crashes when you freed p in destructor?:
Now, let me first ask you, can you free a memory what is already freed. You can write the code, but the behavior is undefined. It may crashes your program or it may do nothing.
Well, in Dummy destructor you've written delete p;. Now, either d2 or d1 would be destroyed first. Let's assume, d2 is destroyed first. So, when d2's destroyer is called, p is freed. Then, d1's destroyer will be called and it'll also try to free p. But p is already freed. And in your case, the program meets a crash for this reason.
Hope, everything is clear to you now.
If anything is not clear about what I've described above, then ask questions, I will try my best to answer them too.

How to comprehend "std::relational operators (shared_ptr) compares directly the stored pointers"

As per the documentation(http://www.cplusplus.com/reference/memory/shared_ptr/operators/), which says:
[emphasis mine]
The comparison compares directly the stored pointers (i.e., the value
the objects dereference to, and not their owned pointer (i.e., the
managed objects that are deleted on destruction), which may not be the
same in alias shared_ptr objects (alias-constructed objects and their
copies).
I can understand the example code in the documentation aforedmentioned to some degree.But I could not comprehend the quotes above.
Could somebody make it clear by giving some simple examlples and explain when using this operator makes sense?
I have been confused for a long time. I would be very grateful to have some help with this question.
Here is the example code which i can understand to some degree:
// shared_ptr relational operators
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> a,b,c,d;
a = std::make_shared<int> (10);
b = std::make_shared<int> (10);
c = b;
std::cout << "comparisons:\n" << std::boolalpha;
std::cout << "a == b: " << (a==b) << '\n';
std::cout << "b == c: " << (b==c) << '\n';
std::cout << "c == d: " << (c==d) << '\n';
std::cout << "a != nullptr: " << (a!=nullptr) << '\n';
std::cout << "b != nullptr: " << (b!=nullptr) << '\n';
std::cout << "c != nullptr: " << (c!=nullptr) << '\n';
std::cout << "d != nullptr: " << (d!=nullptr) << '\n';
return 0;
}
Let's say, you have this struct:
struct Foo { int a, b; };
Then you can generate aliased shared pointers like this:
void f()
{
// create
shared_ptr<Foo> orig(new Foo{1, 2});
// aliased pointer 1, points into object held by orig
shared_ptr<int> pa(orig, &orig->a);
// aliased pointer 2, ditto
shared_ptr<int> pb(orig, &orig->b);
assert(pa != pb); // passes
}
Even though pa and pb share ownership of the same object (which they happen to share with orig as well), they carry different pointers, just like you would expect.
I post an answer which has been deleted by its creator. I think it's helpful to comprehend the example code in the question. Hope it helps to the one who see this question.
A shared_ptr points to an object that it manages. It is the one you get by shared_ptr::get. Expression a == b on shared_ptrs a and b tests whether a and b point to the same object, i.e. whether a.get() == b.get(). It returns true in this case. If a and b point to different objects, even if these two objects compared equal, the result is false.
Let's have a look on the sample code:
a = std::make_shared<int> (10);
b = std::make_shared<int> (10);
This creates two shared pointers pointing to separate integer objects. Even if these two integer objects have the same value 10, they are still different objects. So a.get() will be different from b.get(), and, consequently a==b returns false.
However, once you assign
c = b
the two shared_ptrs b and c will point to the same object, such that b.get() returns a pointer to the same object as c.get(). Hence, c == b returns true.
That a and b point to different objects, whereas b and c share the same object, can be illustrated as follows:
a = std::make_shared<int> (10);
b = std::make_shared<int> (10);
c = b;
*b = 30; // change the value of the managed object.
std::cout << *a << std::endl; // still prints 10;
std::cout << *b << std::endl; // prints 30;
std::cout << *c << std::endl; // prints 30, as it points to the same integral object as b
Hope it got clearer.

Changing the address of a pointer after construction

I've tried to create a minimal example of my problem. I'm trying to check if the address of an void pointer is NULL or not. The address should be overgiven by constructing the class, and should be const. I wrote the class below.
MyPointer.h:
public:
MyPointer(const void* activeApp) : m_activeApp(activeApp){
std::cout <<"adresse on construction: " << m_activeApp << std::endl;
};
MyPointer.cpp:
void printAdress();
private:
const void* m_activeApp;
};
The Methode "printAdress" should be able to print the correct address of the given pointer.
int main(void){
void* p_activeApp = nullptr;
std::cout << p_activeApp << std::endl;
MyPointer myPointer(p_activeApp);
std::cout << "Should be 0: " ;
myPointer.printAddress();
p_activeApp = new(bool);
std::cout << "Should be anything: ";
myPointer.printAddress();
}
void MyPointer::printAddress() {
std::cout << this->m_activeApp << std::endl;
};
Of course it doesn't work, because the m_activeApp still points to NULL, but how can I change this?
If you want to change what myPointer.m_activeApp points to, you have to set the pointer to a different value, simple as that. This pointer and p_activeApp are two distinct, independent pointers. Changing one does not change the other.
What you can do is to make one pointer a reference to the other pointer instead. Then, changing one would also change the other. This will work, though be warned, it won't be good programming style.
Pointers are integers (representing a memory location), so imagine void* to be a number. You set p_activeApp to 0, then you construct a MyPointer, and its internal pointer is set to 0.
Then you change the first number by using the new operator, p_activeApp now gets a value (to that new memory address), but there's no reason for m_activeApp to also change. It still points at 0, no matter what p_activeApp changes to.
I fixed it like this:
public:
MyPointer(void** activeApp) : m_pp_activeApp(activeApp) {
std::cout <<"address on construction: " << *m_pp_activeApp << std::endl;
};
void printAddress();
private:
void** m_pp_activeApp;
};
int main(void){
void* p_activeApp = nullptr;
void** pp_activeApp = &p_activeApp;
MyPointer myPointer(pp_activeApp);
std::cout << "Should be 0: " ;
myPointer.printAddress();
p_activeApp = new(bool);
std::cout << "Should be anything: ";
myPointer.printAddress();
}
void MyPointer::printAddress() {
std::cout << *m_pp_activeApp << std::endl;
};

New pointer in class method must be casted into a reference

I have two classes, let's call them A and B
class A:
{
public:
//Some functions
A *getNewA() const;
private:
//some attributes
}
class B:
{
public:
//Some functions
private:
A &reftoA;
}
In the main code, I must generate a new A thanks to the A::getNewA() method. And this must go to B::reftoA, as written in class B.
Here is the A::getNewA() method :
A *A::getNewA()
{
A *newA = new A;
return newA;
}
OK. So now I call getNewA and want to store the results in reftoA, which is a reference to A. In a B function (which take a reference to A as parameter)
B::foo(A &paramA)
{
reftoA = *(paramA.getNewA());
}
I thought this should have been working, but it won't.
Because when dereferencing, reftoA will always take the this object and not the new allocated object.
Let's be clearer and let's modify the functions to output the results
A * A::getNewA()
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return A;
}
void B::foo(A &paramA)
{
reftoA = *(paramA.getNewA());
std::cout << "new generated pointer " << &reftoA << std::endl;
}
Here is one of the output :
New pointer : 004FFAEC
this pointer: 0069D888
New generated pointer : 0069D888 //Expected : 004FFAEC
I can't get this "new generated pointer" to be the same than the new pointer the A::getNewA() returns after having allocated the memory. Of course, I guess there is some point with dereferencing the pointer to store it in a reference.
I know reference are used with existing object. Maybe the new object A::getNewA() should allocate memory for won't work as I expected.
I could use pointer instead reference in B::foo(), I know, but I can't
I think I am misunderstanding something about refrence and pointer, but I don't know what.
Any help greatly appreciated
The problem is that you can not reassign a reference. You can change only the value of the referenced object.
So you have to initialize the reference in the initializer list of the constructor of the class B.
Take into account that there is a typo in your code snippet
A*A::getNewA()
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return A;
^^^^^^^^^
}
I think you mean
A*A::getNewA() const
^^^^^
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return newA;
^^^^^^^^^^^
}
Always try to provide a verifiable complete example.
Here is a demonstrative program
#include <iostream>
class A
{
public :
//Some functions
A* getNewA() const
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return newA;
}
private :
//some attributes
};
class B
{
public :
B( const A& a ) : reftoA( *a.getNewA() )
{
std::cout << "&reftoA " << &reftoA << std::endl;
}
private :
A& reftoA;
};
int main()
{
A a;
B b( a );
return 0;
}
Its output is
New pointer 0x2b392afbec20
this pointer0x7ffd287ad0af
&reftoA 0x2b392afbec20
As you can see the values of the New pointer and &reftoA are equal each other.
To make it more clear consider a very simple example
#include <iostream>
int main()
{
int x = 10;
int y = 20;
int &r = x;
r = y;
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;
std::cout << "r = " << r << std::endl;
std::cout << std::endl;
std::cout << "&x = " << &x << std::endl;
std::cout << "&y = " << &y << std::endl;
std::cout << "&r = " << &r << std::endl;
return 0;
}
The program output is
x = 20
y = 20
r = 20
&x = 0x7ffd88ad47a8
&y = 0x7ffd88ad47ac
&r = 0x7ffd88ad47a8
This statement
r = y;
did not force the reference to refer the object y. It just reassigned the value of the referenced object x.
References have to be initialized when they are created.
Yes, you are misunderstanding something.
getNewA() is returning a pointer. it's not a smart pointer, you want to look into those and that's all I'll say on the matter.
on returning a pointer, you must keep a reference to this pointer else you will be unable to delete it and you'll get a memory leak. Thus you MUST have somewhere A* a = A::getNewA() and then later, when you no longer need it delete a;
Where you need to pass a reference to A, you can do foo(*a) which will dereference the pointer and pass a reference to the object it's pointing to.
But in summary, for all new code, smart pointers; there's no excuse to not use them.
Side note: Your code example had a few other issues; such as getNewA wasn't static; I'm going to take the code as a working example of your understanding, and not a working example.
Edit: On re-reading your example, the getNewA is intentionally non-static. I think this question is actually an XY problem (ie you're asking a question you've forced yourself into but isn't your actual problem); but I hope this addresses your misunderstanding of pointers and references.
You are not returning the pointer in the getNewA-Method
A* A::getNewA()
{
A *newA = new A;
return A; // you are returning A and not newA
}
And if you want to reassign the reference to a you can use a std::reference_wrapper
class B :
{
public :
void foo(A& paramA) {
reftoA = *(paramA.getNewA());
}
private :
std::reference_wrapper<A> reftoA;
}