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.
Related
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.
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.
I use ESP-32 and need to pass std::shared_ptr using FreeRTOS queue. However, it loose one link. I think that this is source of a problem:
#include <iostream>
#include <memory>
#define PRINT_USE_COUNT(p) std::cout << "Use count: " << p.use_count() << std::endl;
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
}
class testClass {
public:
testClass() {
std::cout << "Class is constructed" << std::endl;
};
virtual ~testClass() {
std::cout << "Class is destructed" << std::endl;
};
};
struct container {
std::shared_ptr<testClass> field;
};
extern "C" void app_main(void) {
auto queue = xQueueCreate(1, sizeof(container));
auto p = std::make_shared<testClass>();
PRINT_USE_COUNT(p); // 1
{
container c;
c.field = p;
PRINT_USE_COUNT(p); // 2
xQueueSendToBack(queue, &c, 0);
PRINT_USE_COUNT(p); // 2
}
PRINT_USE_COUNT(p); // 1 (Ooops!)
{
container c;
assert(xQueueReceive(queue, &c, 0) == pdTRUE);
PRINT_USE_COUNT(c.field); // 1
}
// Class is destructed
std::cout << "Test finished" << std::endl;
vQueueDelete(queue);
}
So there is a pointer in queue, but it isn't counted!
How can I solve this issue (and keep using FreeRTOS queue if possible)? Using std::move doesn't help.
A C-style queue of raw pointers will only works for C++ shared_ptr iff std::is_trivial<T>::value is true (mainly POD or trivially copyable object).
Since there are memcpy and other plain C operation manipulating memory the reference count will not be handled properly (because it is C-code behind the scene and it does not call destructor among other thing) and you could end up with a memory leak.
There is no easy way to circumvent this, but the best way is to manage the memory yourself.
See this question also : Shared pointers and queues in FreeRTOS
I managed to transform unique pointer into a raw format which could be sent via a message queue.
See here: https://codereview.stackexchange.com/questions/241886/using-unique-ptr-in-freertos.
Please note I posted it in code review because I am not sure whether there are really no memory leaks or this can be implemented much more cleanly.
I will test whether I can actually use this for the IPC in our project.
I don't always agree that developing something from scratch is best option. Using something that is well tested might be best option in most occasions even-though it could require some tweaking for making it fit to your needs.
With the queue you can pass a dynamically created instance of your container. It is very rare, if it is at all, to use a queue for sending data from one task to same task, as the example above. I don't like pretty much working with dynamic allocations in embedded CPUs, the overhead can sometimes impact performance too much.
Here below is a working PoC where, instead of a raw copy, a pointer to a new container instance is passed. In this approach it is the responsibility of the receiving task to release the instance to avoid memory leaks.
extern "C" {
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
}
#include <iostream>
#include <memory>
#define PRINT_USE_COUNT(p) std::cout << "Use count: " << p.use_count() << std::endl;
class testClass {
public:
testClass() {
std::cout << "testClass constructed" << std::endl;
}
~testClass() {
std::cout << "testClass destructed" << std::endl;
}
};
class myContainer {
public:
myContainer(std::shared_ptr<testClass> p) {
_p = p;
std::cout << "myContainer constructed" << std::endl;
}
~myContainer() {
std::cout << "myContainer destructed" << std::endl;
}
std::shared_ptr<testClass>& p() {
return _p;
}
private:
std::shared_ptr<testClass> _p;
};
extern "C" void app_main(void) {
std::cout << "Start of test, creating the shared_ptr..." << std::endl;
auto p = std::make_shared<testClass>();
PRINT_USE_COUNT(p);
std::cout << "Creating one container..." << std::endl;
myContainer c(p);
PRINT_USE_COUNT(p);
std::cout << "Creating the queue..." << std::endl;
auto q = xQueueCreate(1, sizeof(myContainer*));
std::cout << "Sending a dynamically created item to the queue..."
<< std::endl;
myContainer *cp = new myContainer(p);
xQueueSendToBack(q, &cp, 0);
PRINT_USE_COUNT(p);
{
myContainer *pc;
xQueueReceive(q, &pc, 0);
PRINT_USE_COUNT(p);
std::cout << "Use count of pc->p() " << pc->p().use_count()
<< std::endl;
std::cout << "Freeing the dynamically created item..." << std::endl;
delete pc;
PRINT_USE_COUNT(p);
}
std::cout << "end of test" << std::endl;
}
Here's the program's output:
Start of test, creating the shared_ptr...
testClass constructed
Use count: 1
Creating one container...
myContainer constructed
Use count: 2
Creating the queue...
Sending a dynamically created item to the queue...
myContainer constructed
Use count: 3
Use count: 3
Use count of pc->p() 3
Freeing the dynamically created item...
myContainer destructed
Use count: 2
end of test
myContainer destructed
testClass destructed
Suppose I have the following code in C++:
#include <memory>
#include <iostream>
struct Some {
Some(int _a) : a(_a) {}
int a;
};
int main() {
Some some(5);
std::unique_ptr<Some> p1 = std::make_unique<Some>(some);
std::unique_ptr<Some> p2 = std::make_unique<Some>(some);
std::cout << p1->a << " " << p2->a << std::endl;
return 0;
}
As I understand, unique pointers are used to guarantee that resources are not shared. But in this case both p1 and p2 point to the same instance some.
Please unveil the situation.
They don't point to the same resource, they each point to a different copy of it. You can illustrate it by deleting the copy constructor to see the error:
#include <memory>
#include <iostream>
struct Some {
Some(int _a) : a(_a) {}
Some(Some const&) = delete;
int a;
};
int main() {
Some some(5);
std::unique_ptr<Some> p1 = std::make_unique<Some>(some); //error here
std::unique_ptr<Some> p2 = std::make_unique<Some>(some);
std::cout << p1->a << " " << p2->a << std::endl;
return 0;
}
std::make_unique creates objects, calling constructor with specified arguments.
You passed Some& as parameter, and here copy constructor was invoked, and new object constructed.
So, p1 and p2 are 2 absolutely different pointers, but constructed from same object, using copy constructor
both p1 and p2 point to the same instance some
No, they don't.
#include <memory>
#include <iostream>
struct Some {
Some(int _a) : a(_a) {}
int a;
};
int main() {
Some some(5);
std::unique_ptr<Some> p1 = std::make_unique<Some>(some);
std::unique_ptr<Some> p2 = std::make_unique<Some>(some);
std::cout << p1->a << " " << p2->a << std::endl;
p1->a = 42;
std::cout << p1->a << " " << p2->a << std::endl;
return 0;
}
output:
5 5
42 5
To test whether two pointers point to the same object instance, you should compare the locations they point to, instead of the object member variables:
std::cout << &(*p1) << " " << &(*p2) << std::endl;
Which will show that they indeed do not point to the same instance.
ADDENDUM: As pointed out by Remy Lebeau, since C++11 it is advisable to use the
std::addressof function for this purpose, which obtains the actual address of an object even if the & operator is overloaded:
std::cout << std::addressof(*p1) << " " << std::addressof(*p2) << std::endl;
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.