How does counter decrement of smart pointer work? - c++

Below is a sample code for shared pointer. I define a shared pointer inside curly braces scope. sp1 is initialized by new A (counter = 1) and sp1 is assigned to sp2 (copy and/or assignment increase the counter by 1 so, counter = 2). I always thought destructor of the A is called when counter becomes 0. But in my case the smart pointer when is about to get out of scope ( via the curly brace ) the counter is two.
My question is : who changed the counter from 2 to 0?
#include <iostream>
#include <memory>
using namespace std;
class A{
public:
~A(){
std::cout << "~A" << std::endl;
}
};
int main(){
{
shared_ptr<A> sp1 (new A);
shared_ptr<A> sp2 = sp1;
std::cout << "sp1 count = " << sp1.use_count() << std::endl;
std::cout << "sp2 count = " << sp2.use_count() << std::endl;
}
return 0;
}
EDIT:
Link to paper on smart pointer
output:
sp1 count = 2
sp2 count = 2
~A

When your code gets to the end of main, the destructor for both sp1 and sp2 runs, which decrements the counter to zero - that is a VERY important part of shared pointers, that the destructor reduces the reference count and thus, when "nothing" is left, the destructor of the actual shared object gets called.
The destuctor of shared_ptr will have some logic like this:
counter--; // Should be atomic!
if (counter == 0)
{
delete owned_thing;
}

A better example (IMO) would be something like this:
int main()
{
std::shared_ptr<A> sp1{new A};
std::cout << "1: sp1.use_count() = " << sp1.use_count() << '\n';
{
std::shared_ptr<A> sp2 = sp1;
std::cout << "2: sp1.use_count() = " << sp1.use_count() << '\n';
std::cout << "2: sp2.use_count() = " << sp2.use_count() << '\n';
}
std::cout << "3: sp1.use_count() = " << sp1.use_count() << '\n';
}
The output from this program should be (using your class with its destructor):
1: sp1.use_count() = 1
2: sp1.use_count() = 2
2: sp2.use_count() = 2
3: sp1.use_count() = 1
~A
First you create a shared pointer and initialize it, making the use counter 1. Then you enter a new scope and in it create a new shared pointer initializing it (using the shared pointers copy-constructor) with the old pointer, leading to the use count of both pointers being 2. Then the second shared pointer goes out of scope, and the shared pointer destructor decrements the use count by one. Finally the second shared pointer goes out of scope, as the main function returns, and the use count is decremented by the sp1 destructor. Now it has reached zero, and the contained pointer is deleted resulting in the A destructor being called.

Related

I can copy or pass by value unique pointers, how is this possible?

What I've read from multiple sources states that, An unique_ptr cannot be copied to another unique_ptr, passed by value to a function, or used in any C++ Standard Library algorithm that requires copies to be made. However, I can seem to be able to do all those things.
#include <iostream>
#include <memory>
int test(int copy)
{
std::cout << "copy: " << copy << std::endl;
return copy;
}
int main()
{
std::unique_ptr<int> uniquePtr1(new int(4));
std::cout << "*uniquePtr1: " << *uniquePtr1 << std::endl;
int num1 = *uniquePtr1;
std::cout << "num1: " << num1 << std::endl;
int num2 = test(*uniquePtr1);
std::cout << "num2: " << num2 << std::endl;
int *ptr1 = new int;
*ptr1 = *uniquePtr1;
std::cout << "*ptr1: " << *ptr1 << std::endl;
std::unique_ptr<int> uniquePtr2(new int);
*uniquePtr2 = *uniquePtr1;
std::cout << "*uniquePtr2: " << *uniquePtr2 << std::endl;
delete ptr2;
}
Output:
*uniquePtr1: 4
num1: 4
copy: 4
num2: 4
*ptr2: 4
*uniquePtr2: 4
Am I missing something? Links are also appreciated.
You indeed can't copy a unique pointer, this won't compile:
std::unique_ptr<int> uniquePtr1(new int(4));
std::unique_ptr<int> uniquePtr2(uniquePtr1);
You'd need to move uniquePtr1 into uniquePtr2:
std::unique_ptr<int> uniquePtr2(std::move(uniquePtr1));
What your code is doing is copying the value pointed to by the pointer.
A useful analogy would be a pointer being equivalent to a box and the value of that pointer being a ball in the box. A unique box can't hold the same ball as any other box but it is possible to look at the ball in the first unique box and add a ball of the same colour to another unique box. You now have two unique boxes, both containing red balls but not the same red ball. If you were now to paint one of the balls blue the other ball would still be red.
Expanding this analogy to shared pointers (or bare pointers) requires some balls that can exist in multiple places at the same time. With a shared box you can have the same ball in two different shared boxes and painting one ball will also change the colour of the ball in the other box.
Back to code:
std::unique_ptr<int> uniquePtr1(new int(4));
std::cout << *uniquePtr1; // 4
std::unique_ptr<int> uniquePtr2(new int(*uniquePtr1));
std::cout << *uniquePtr1; // 4
std::cout << *uniquePtr2; // 4
*uniquePtr1 = 5;
std::cout << *uniquePtr1; // 5
std::cout << *uniquePtr2; // still 4
Though uniquePtr1 point to ints with the same value they are separate objects and updating one doesn't update the other.
With shared pointers we can copy the pointer rather than the value:
std::shared_ptr<int> sharedPtr1(new int(4));
std::cout << *sharedPtr1; // 4
std::shared_ptr<int> sharedPtr2(new int(*sharedPtr1)); // copy the value into a new pointer
std::shared_ptr<int> sharedPtr3(sharedPtr1); // copy the pointer
std::cout << *sharedPtr1; // 4
std::cout << *sharedPtr2; // 4
std::cout << *sharedPtr3; // 4
*sharedPtr1= 5;
std::cout << *sharedPtr1; // 5
std::cout << *sharedPtr2; // still 4
std::cout << *sharedPtr3; // 5
You haven't copied any unique_ptr, you're just coping the value it's pointing to.
Try these:
/// (1)
void f(unique_ptr<int>);
unique_ptr<int> p = make_unique(1);
f(p);
/// (2)
unique_ptr<int> p = make_unique(2);
unique_ptr<int> q = p;
The confusion seems to be on what it means to copy, rather than any specific confusion with unique_ptr.

C++ shared_from_this() is not letting obj get destructed

I have a following piece of code, which is creating a simple object of Name and inside that it is creating another object Name, with a shared_from_this() reference. As I am reading from here
https://en.cppreference.com/w/cpp/memory/enable_shared_from_this/shared_from_this
"Effectively executes std::shared_ptr(weak_this), where weak_this is the private mutable std::weak_ptr member of enable_shared_from_this."
Which I am understanding as shared_from_this() is only creating a weak pointer to shared obj. But I don't see this is the case in runtime. There is effectively a circular reference getting created.
At the end of the I was expecting the Name obj should be destructed, but it is not because the reference counter is 2.
Can someone help me understand how should I use enable_shared_from_this(), that can effectively cleanup the Name obj, once it goes out of reference.
#include <iostream>
#include <memory>
#include <string>
#include <chrono>
#include <thread>
using namespace std;
struct Another;
struct Name : public std::enable_shared_from_this<Name> {
std::string t;
int m, n, p;
shared_ptr<Another> ann;
Name() {
std::cout << "constructor\n";
}
void MakeSomething() {
ann = std::make_shared<Another>(shared_from_this());
}
~Name() {
std::cout << "destructor\n";
}
};
struct Another {
shared_ptr<Name> nn;
Another(shared_ptr<Name> n) : nn(n) {
std::cout << "from another constructor " << nn.use_count() << "\n";
}
~Another() {
std::cout << "from another destructor\n";
}
};
int main()
{
{
auto n = std::make_shared<Name>();
std::cout << "Name ref count so far: " << n.use_count() << "\n";
auto p = n.get();
//delete p;
std::cout << "Name ref count so far: " << n.use_count() << "\n";
n->MakeSomething();
std::cout << "Name ref count so far: " << n.use_count() << "\n";
{
shared_ptr<Name> m = n;
std::cout << "Name ref count so far: " << n.use_count() << "\n";
}
std::cout << "Name ref count so far: " << n.use_count() << "\n";
}
// problem: at this point Name obj, should go out of reference and destructor to be called, which is NOT happening
return 0;
}
And here is the runtime output (compiler used msvc)
constructor
Name ref count so far: 1
Name ref count so far: 1
from another constructor 3
Name ref count so far: 2
Name ref count so far: 3
Name ref count so far: 2
Which I am understanding as shared_from_this() is only creating a weak pointer to shared obj. But I don't see this is the case in runtime. There is effectively a circular reference getting created.
shared_from_this() is creating a weak_ptr, which you're passing to a shared_ptr constructor, as specified by (11) here. That constructor creates a shared_ptr to the same object, increasing the reference count.
Also keep in mind that weak_ptr does not contribute to the reference count at all, so it has no bearing on your confusion over the reference count. Focus on what the shared_ptrs are doing.

Cpp thread object and shared_ptr issue

When I read the document in cppreference here
https://en.cppreference.com/w/cpp/memory/shared_ptr#Example
I am wondering what the possible value of the first lp.use_count() printed out is? I marked it with "<<<<<" in output content.
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
struct Base
{
Base() { std::cout << " Base::Base()\n"; }
// Note: non-virtual destructor is OK here
~Base() { std::cout << " Base::~Base()\n"; }
};
struct Derived: public Base
{
Derived() { std::cout << " Derived::Derived()\n"; }
~Derived() { std::cout << " Derived::~Derived()\n"; }
};
void thr(std::shared_ptr<Base> p)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::shared_ptr<Base> lp = p; // thread-safe, even though the
// shared use_count is incremented
{
static std::mutex io_mutex;
std::lock_guard<std::mutex> lk(io_mutex);
std::cout << "local pointer in a thread:\n"
<< " lp.get() = " << lp.get()
<< ", lp.use_count() = " << lp.use_count() << '\n';
}
}
int main()
{
std::shared_ptr<Base> p = std::make_shared<Derived>();
std::cout << "Created a shared Derived (as a pointer to Base)\n"
<< " p.get() = " << p.get()
<< ", p.use_count() = " << p.use_count() << '\n';
std::thread t1(thr, p), t2(thr, p), t3(thr, p);
p.reset(); // release ownership from main
std::cout << "Shared ownership between 3 threads and released\n"
<< "ownership from main:\n"
<< " p.get() = " << p.get()
<< ", p.use_count() = " << p.use_count() << '\n';
t1.join(); t2.join(); t3.join();
std::cout << "All threads completed, the last one deleted Derived\n";
}
Possible output:
Base::Base()
Derived::Derived()
Created a shared Derived (as a pointer to Base)
p.get() = 0x2299b30, p.use_count() = 1
Shared ownership between 3 threads and released
ownership from main:
p.get() = 0, p.use_count() = 0
local pointer in a thread:
lp.get() = 0x2299b30, lp.use_count() = 5 <<<<<<<< HERE <<<<<<
local pointer in a thread:
lp.get() = 0x2299b30, lp.use_count() = 3
local pointer in a thread:
lp.get() = 0x2299b30, lp.use_count() = 2
Derived::~Derived()
Base::~Base()
All threads completed, the last one deleted Derived
#user2452809 's answer is very appreciated, which pointed out an important feature of use_count().
Supposing use_count() would return an accurate count, what would be the answer?
I wouldn't rely on that value anyway.
In multithreaded environment, the value returned by use_count is approximate (typical implementations use a memory_order_relaxed load)
Check the reference for more information: https://en.cppreference.com/w/cpp/memory/shared_ptr/use_count
I think it could be one value of {4,5,6}. Am I right?
Q: Why larger than 3?
A: When printing, at least one thr function is invoked. Including the reference in main function. the use_count should be 3. But it's not possible when one thread sleep for one second and other two hadnot been constructed.
On the other hand, if there're two threads finished, the last thread would have a use_count 3. But it would not be the first line because of the thread mutex in printing scope.
Q: Why less than 7?
A: Because during the sleep in subthread, the main thread will run p.reset(). One second is a quite long time to CPU.

thread_local static class is destroyed at invalid address on program exit

I have an issue with the destruction of a thread_local static object.
#include <iostream>
#include <thread>
struct UsesLoc {
UsesLoc() {
loc.counter++;
}
struct Loc {
Loc() {
std::cout << "I am at " << this << " and counter is " << counter << std::endl;
}
~Loc() {
std::cout << "I was at " << this << " and counter is " << counter << std::endl;
}
int counter = 0;
};
static thread_local Loc loc;
};
thread_local UsesLoc::Loc UsesLoc::loc;
int main()
{
{
UsesLoc usesloc;
std::cout << "loc is at " << &UsesLoc::loc << " and counter is " << UsesLoc::loc.counter << std::endl;
}
return 0;
}
As expected, compiling and running on https://coliru.stacked-crooked.com/a/e8bcfdaffa6a6da7 reveals that the thread_local object is always at the same location and the counter values are (0,1,1):
I am at 0x7f9dc817673c and counter is 0
loc is at 0x7f9dc817673c and counter is 1
I was at 0x7f9dc817673c and counter is 1
Conversely, when I locally compile with MinGW and run, I get, for instance,
I am at 0x507874 and counter is 0
loc is at 0x507874 and counter is 1
I was at 0x7efdd000 and counter is 2686552
Clearly, an uninitialized object at a different memory location is destroyed.
Did I oversee anything non-deterministic? How can I ensure that the correct object is destroyed?
After getting a hint from Ted Lyngmo that this might be a compiler bug, I did a bit of research and it seems to be indeed an issue already reported before:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83562
https://sourceforge.net/p/mingw-w64/bugs/527/
https://sourceforge.net/p/mingw-w64/bugs/727/
That being said, the code is correct and the pointer to the object being destructed points to the same object that was constructed before when using a standard-compliant compiler.

Strange behavior of pointers in c++

Following results are very interesting and I am having difficulty understanding them. Basically I have a class which has an int:
class TestClass{
public:
int test;
TestClass() { test = 0; };
TestClass(int _test) { test = _test; };
~TestClass() { /*do nothing*/ };
};
A test function which accepts a pointer of TestClass
void testFunction1(TestClass *ref){
delete ref;
TestClass *locTest = new TestClass();
ref = locTest;
ref->test = 2;
cout << "test in testFunction1: " << ref->test << endl;
}
This is what I am doing in main:
int main(int argc, _TCHAR* argv[])
{
TestClass *testObj = new TestClass(1);
cout << "test before: " << testObj->test << endl;
testFunction1(testObj);
cout << "test after: " << testObj->test << endl;
return 0;
}
I was expecting output to be:
test before: 1
test in testFunction1: 2
test after: 1
But I get the following output:
test before: 1
test in testFunction1: 2
test after: 2
Can someone explain this. Interesting thing is that changing testFunction1 to:
void testFunction1(TestClass *ref){
//delete ref;
TestClass *locTest = new TestClass();
ref = locTest;
ref->test = 2;
cout << "test in testFunction1: " << ref->test << endl;
}
i.e. I do not delete ref before pointing it to new location, I get the following output:
test before: 1
test in testFunction1: 2
test after: 1
I would really appreciate if someone can explain me this strange behavior. Thanks.
When you access the object after deleting it, the behaviour is undefined.
The behaviour that you see follows from the memory allocation algorithm in your system.
That is after deleting your first testclass object, you allocate memory for a new object. The runtime simply reuses the memory.
To check what is going on, print the values of the pointers:
void testFunction1(TestClass *ref){
cout << ref << endl;
delete ref;
TestClass *locTest = new TestClass();
cout << locTest << endl;
ref = locTest;
ref->test = 2;
cout << "test in testFunction1: " << ref->test << endl;
}
You get a copy of the pointer to the object in testFunction1(), so when you assign to it, the original value of the pointer in main() does not change
Also, you are deleting the object (by calling delete in testFunction1()) to which the original pointer (in main()) is pointing, but as the value in main() is not updated, you are accessing an invalid object -- the fact that you can read the value that you set in testFunction1(), is a coincidence and cannot be relied on
The fact that you correctly read the original value in the second case (when you don't call delete) is because the original object has not been changed (you change a new one in testFinction1 and the pointer to it in main is the same (as explained above) and the object is still alive
in this case , you just got the new object at the same address with the old one you delete.
actually testObj became a dangling pointer after you call testFunction1.
void testFunction1(TestClass *ref){
delete ref;
TestClass *locTest = new TestClass();
cout << "locTest = " << locTest << endl;
ref = locTest;
ref->test = 2;
cout << "test in testFunction1: " << ref->test << endl;
}
int main(int argc, char * argv[])
{
TestClass *testObj = new TestClass(1);
cout << "test before: " << testObj->test << endl;
cout << "testObg = " << testObj << endl;
testFunction1(testObj);
cout << "test after: " << testObj->test << endl;
cout << "testObg = " << testObj << endl;
return 0;
}
Output is :
test before: 1
testObg = 0x511818
locTest = 0x511818
test in testFunction1: 2
test after: 2
testObg = 0x511818
After this instruction:
TestClass *testObj = new TestClass(1);
you have allocated a new memory area containing a TestClass object, whose address (let's call it maddr) is stored into testObj.
Now, this instruction:
cout << "test before: " << testObj->test << endl;
outputs 1, as expected.
Inside testFunction1() you have a local variable called ref, which is a pointer containing the value maddr.
When you delete ref, you deallocate the area of memory containing a TestClass object, whose address is maddr.
Then you allocate a new memory area:
TestClass *locTest = new TestClass();
and locTest contains its address, let's call it m1addr.
Then you use ref to access the memory area at m1addr and change the int test value to 2.
This instruction:
cout << "test in testFunction1: " << ref->test << endl;
outputs 2 as expected.
Now, back to main, you have lost any handler to the area containing a TestClass object whose address is m1addr (that is, you are leaking memory) and the area pointed to by testObj is not allocated anymore.
When you use testObj again, you access an area of memory starting at maddr, which has been cleaned. The effect of accessing testObj->test is undefined behavior.
What you experience could be do to the fact that when you run your code maddr == m1addr, but this can only happen by chance, you cannot rely on this.
Odds are the new object (with a 2) is being created where the old deleted object (with a 1) used to be. Your original pointer still points to that location so when you access it you accidentally access the new object (with a 2).
TestClass *ref in the parameter to testFunction1 and TestClass *testObj in main are 2 different pointers to the same thing, they are not the same pointer though. If you want to delete and reallocate an object inside a function/method you can use a pointer to a pointer as the parameter.
As others have mentioned , after testfunction1 you're accessing an object that was deleted within testfunction1 which as also mentioned is undefined behaviour. The memory being pointed to by the dangling pointer was released during the delete but the contents are likely to still be there until the memory location is reallocated during another call to new. So you are using unallocated space that could be overwritten very easily at anytime.
Hope this helps