Boost shared_ptr on class object - c++

Say I have the following code:
controller.hpp
#include "testing.hpp"
#include <boost/shared_ptr.hpp>
class controller
{
public:
controller(void);
void test_func (void);
boost::shared_ptr <testing> _testing;
}
controller.cpp
#include "controller.hpp"
controller::controller() {
boost::shared_ptr <testing> _testing (new testing);
std::cout << _testing->test_bool << std::endl;
}
void controller::test_func (void) {
// how to use _testing object?
std::cout << _testing->test_bool << std::endl;
return;
}
int main (void) {
controller _controller; // constructor called
test_func();
return 0;
}
testing.hpp
class testing
{
public:
bool test_bool = true;
}
Am I using a shared_ptr properly here for a class member? Multiple functions in class controller need to use the _testing object, and I don't want the testing classes' constructor / deconstructor to be called every time the pointer goes out of scope. Maybe this cant' be avoided, I'm starting to realize.

The testing object get constructed in controller constructor and destructed when it go out of the scope.
Just:
int main (void) {
controller _controller; // constructor called
_controller.test_func();
// destructor of controller called, because it go out of scope,
// so testing destructor is called too because, there is no more
// shared_ptr pointing to it!
}
[EDITED] To match question owner edits

I've taken the liberty of rewriting your code to demonstrate a usage of a shared pointer. Pretty typically it is used so an object can be in two places at once, moved around, and destruction is automatic.
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
class testing
{
public:
std::string str;
testing( const char* in ) : str( in ) { }
};
typedef boost::shared_ptr <testing> SP_testing;
class controller
{
public:
controller( const char* in );
void test_func ( );
SP_testing _testing;
};
controller::controller( const char* in )
:_testing( boost::make_shared< testing >( in ) )
{
std::cout << "controller constructor: \"" << _testing->str << '\"' << std::endl;
}
void controller::test_func (void) {
std::cout << "test_func: \"" << _testing->str << "\" - cnt: " << _testing.use_count( ) << std::endl;
}
int main (void)
{
//yet to be used shared pointer
SP_testing outsider;
{
//this will create an instance of testing.
controller _controller( "this is a test" ); // constructor called, prints
outsider= _controller._testing; //assign shared pointer
_controller.test_func( ); // test called, prints usage count.
}//leaving scope, _controller will be destroyed but the _testing it created will not
std::cout << "outsider: \"" << outsider->str << "\" - cnt: " << outsider.use_count( ) << std::endl;
//now testing will get destroyed.
return 0;
}
Above, 'outsider' took a pointer to controller::_testing. At test_func they both have a pointer to the same object. Even though controller create the testing object it does not get destroyed when controller gets destroyed. Very handy when these kind of situations arise. This code can be pasted into one .cpp file. Thanks to #Dan MaĊĦek for the heads up on make_shared

Related

std::map object destructor getting called?

I have a global map object which contains an ID and a class object, but I don't understand why the destructor for the objects in the map are getting called.
#include <map>
#include <iostream>
#include <cassert>
#include <chrono>
#include <thread>
class TestMapObject{
private:
std::string m_sName;
public:
TestMapObject(const std::string& sName){
std::cout << "Constructor called" << std::endl;
m_sName = sName;
}
~TestMapObject(){
std::cout << "Destructor called" << std::endl;
}
const std::string& GetName(){
return m_sName;
}
};
namespace Test{
enum ETestMapKeyId{
k_ETestMapKeyNone = 0,
k_ETestMapKeyFirst,
k_ETestMapKeySecond,
};
std::map<ETestMapKeyId, TestMapObject> g_tMap;
TestMapObject* GetMapObjectById(ETestMapKeyId eID){
auto itFound = g_tMap.find(eID);
assert(itFound != g_tMap.end());
return &itFound->second;
}
}
int main(){
Test::g_tMap.insert(std::pair<Test::ETestMapKeyId,TestMapObject>(Test::k_ETestMapKeyFirst,TestMapObject("Alice")));
Test::g_tMap.insert(std::pair<Test::ETestMapKeyId,TestMapObject>(Test::k_ETestMapKeySecond,TestMapObject("Mocha")));
//destructor gets called here
std::cout << " are we destructed? " << std::endl;
TestMapObject* tmKeyFirst = Test::GetMapObjectById(Test::k_ETestMapKeyFirst);
TestMapObject* tmKeySecond = Test::GetMapObjectById(Test::k_ETestMapKeySecond);
for(;;){
std::this_thread::sleep_for (std::chrono::seconds(1));
std::cout << tmKeyFirst->GetName() << std::endl ;
std::cout << tmKeySecond->GetName() << std::endl ;
}
return 0;
}
I'm able to retrieve a pointer to the objects with GetMapObjectById and continuously able to print their name (Which might be undefined behavior considering their destructor was called). But I'm unsure why the destructor gets called before the application ends..
Output
Constructor called
Destructor called
Destructor called
Constructor called
Destructor called
Destructor called
are we destructed?
---continues loop print
Alice
Mocha
What you see is not the std::map getting destroyed, but the temporaries you are using to insert elements in the map. You can use emplace to avoid the construction (and destruction) of that temporaries:
Test::g_tMap.emplace(Test::k_ETestMapKeyFirst,"Alice");
Test::g_tMap.emplace(Test::k_ETestMapKeySecond,"Mocha");
Live Demo

How to delay destruction of static object (logger) in C++?

I got a class which holds the application's logger as a unique_ptr. The logger can be set through a static function. Also, one can obviously log messages. I left out any thread synchronization (mutexes) to make things easier.
class LoggerWrapper {
public:
static void SetLogger(std::unique_ptr<logger::ILogger> new_logger);
static void Log(const std::string& message);
private:
static std::unique_ptr<logger::ILogger> logger_;
};
void LoggerWrapper::Log(const std::string& message) {
if (!logger_) {
// cannot log
} else {
logger_->OnLogEvent(message);
}
}
void LoggerWrapper::SetLogger(std::unique_ptr<logger::ILogger> new_logger) {
logger_ = std::move(new_logger);
}
My problem is: The unique_ptr gets destructed before some of the other classes inside the application. E.g. is the DTOR of Class Foo wants to log something, the unique_ptr might have already been destroyed (which is the case at the moment). This causes the ILogger implementation to be destroyed, resulting in no log output being possible.
Does anyone have an idea on how to easily fix this? I somehow need to "delay" the destruction of the static unique_ptr. I also tried changing it to a shared_ptr, but that only caused SIGABRTs with "pure virtual method called" errors.
Thanks in advance!
EDIT: Created a minimal working example which contradicts my experience. In this case, the static logger outlives the Foo class.
EDIT2: My application uses exit. That seems to change the order of destruction.
EDIT3: exit does not destroy local objects.
/******************************************************************************
Online C++ Compiler.
Code, Compile, Run and Debug C++ program online.
Write your code in this editor and press "Run" button to compile and execute it.
*******************************************************************************/
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class ILogger {
public:
ILogger() {
std::cout << "ILogger CTOR" << std::endl;
}
~ILogger() {
std::cout << "ILogger DTOR" << std::endl;
}
virtual void OnLogEvent(const std::string& log_message) {
std::cout << "OnLogEvent: " << log_message << std::endl;
}
};
class LoggerWrapper {
public:
static void SetLogger(std::unique_ptr<ILogger> new_logger) {
logger_ = std::move(new_logger);
}
static void Log(const std::string& message) {
if (!logger_) {
// cannot log
} else {
logger_->OnLogEvent(message);
}
};
private:
static std::unique_ptr<ILogger> logger_;
};
class Foo {
public:
Foo(const std::string& name) : name_{name} {
LoggerWrapper::Log(name_ + ": CTOR");
}
~Foo() {
LoggerWrapper::Log(name_ + ": DTOR");
}
private:
std::string name_;
};
// declaring logger_ first causes it to be deleted AFTER foo
std::unique_ptr<ILogger> LoggerWrapper::logger_;
std::unique_ptr<Foo> foo;
int main()
{
LoggerWrapper::SetLogger(std::make_unique<ILogger>());
foo = std::make_unique<Foo>("Global FOO");
// local variables do NOT get destroyed when calling exit!
auto foo_local = Foo("Local FOO");
exit(1);
}
This is trivial.
First you don't use global static objects ( you should not be using global state like that). You use function static objects so you can control the order of creation/destruction.
So change this:
std::unique_ptr<ILogger> LoggerWrapper::logger_;
std::unique_ptr<Foo> foo;
Into:
class GlobalLogger
{
public:
ILogger& getLogger() {
static ILogger logger; // if you must use unique_ptr you can do that here
return logger; // But much simpler to use a normal object.
}
};
class GlobalFoo
{
public:
Foo& getFoo() {
// If there is a chance that foo is going to
// use global logger in its destructor
// then it should simply call `GlobalLogger::getLogger()`
// in the constructor of Foo. You then
// guarantee the order of creation and thus destruction.
// Alternatively, you can call it here in thus
// function just before the declaration of foo.
static Foo foo;
return foo;
}
};
// Where you were using `logger_` use `GlobalLogger::getLogger()`
// Where you were using `foo` use `GlobalFoo::getFoo()`
If we use your original code as the starting point we can do this:
#include <iostream>
#include <memory>
#include <string>
// Please don't do this.
// This is the number one worst practice.
// https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice
using namespace std;
class ILogger {
public:
ILogger() {
std::cout << "ILogger CTOR" << std::endl;
}
~ILogger() {
std::cout << "ILogger DTOR" << std::endl;
}
virtual void OnLogEvent(const std::string& log_message) {
std::cout << "OnLogEvent: " << log_message << std::endl;
}
};
class LoggerWrapper
{
// Here store the logger
// as a static member of this private function.
// The the SetLogger() Log() functions get this reference.
static std::unique_ptr<ILogger>& getLogReference() {
static std::unique_ptr<ILogger> logger;
return logger;
}
public:
static void SetLogger(std::unique_ptr<ILogger> new_logger) {
// Save the new reference.
getLogReference() = std::move(new_logger);
}
// Use the logger if it has been set.
static void Log(const std::string& message) {
std::unique_ptr<ILogger>& logger_ = getLogReference();
if (!logger_) {
// cannot log
} else {
logger_->OnLogEvent(message);
}
};
};
class Foo {
public:
Foo(const std::string& name) : name_{name} {
// This calls Log()
// Which calls getLogReference()
// Which forces the creation of the function static
// variable logger so it is created before this
// object is fully initialized (if it has not already
// been created).
//
// This means this object was created after the logger
LoggerWrapper::Log(name_ + ": CTOR");
}
~Foo() {
// Because the Log() function was called in the
// constructor we know the loger was fully constructed first
// thus this object will be destroyed first
// so the logger object is guaranteed to be
// available in this objects destructor
// so it is safe to use.
LoggerWrapper::Log(name_ + ": DTOR");
}
private:
std::string name_;
};
std::unique_ptr<Foo>& globalFoo() {
// foo may destroy an object created later
// that has a destructor that calls LoggerWrapper::Log()
// So we need to call the Log function here before foo
// is created.
LoggerWrapper::Log("Initializing Global foo");
// Note: Unless somebody else has explicitly called SetLogger()
// the above line is unlikely to log anything as the logger
// will be null at this point.
static std::unique_ptr<Foo> foo;
return foo;
}
int main()
{
LoggerWrapper::SetLogger(std::make_unique<ILogger>());
globalFoo() = std::make_unique<Foo>("Global FOO");
// local variables do NOT get destroyed when calling exit!
auto foo_local = Foo("Local FOO");
exit(1);
}
The order in which static (global) objects are created and destroyed is undefined. This leave you a few options.
Don't use global objects, just raw use pointers which you can destroy yourself in the correct order.
Use a pointer to your logger that you never destroy. This technically is a memory leak but the kernel will cleanup when your application exits.
Use a shared_ptr for your logger. Each object that uses the logger gets a shared_ptr and the logger will be cleaned up after the last object is destroyed.

C++ - shared_ptr of abstract class

I have the following code:
#include <string>
#include <queue>
#include <thread>
#include <iostream>
using namespace std;
class MsgType {
public:
virtual string getData() const = 0;
static MsgType* getMsg();
};
class Msg1 : public MsgType {
string getData() const override final {
return "Msg1";
}
};
class Msg2 : public MsgType {
string getData() const override final {
return "Msg2";
}
};
queue<shared_ptr<MsgType>> allMsgs;
MsgType* MsgType::getMsg() {
shared_ptr<MsgType> msg_sp = nullptr;
if (!allMsgs.empty()) {
msg_sp = allMsgs.front();
allMsgs.pop();
}
if (msg_sp) {
MsgType* mt = msg_sp.get();
cout << "[in the method] " << mt->getData() << endl;
return mt;
} else {
return nullptr;
}
}
int main() {
MsgType* msg1 = new Msg1();
MsgType* msg2 = new Msg2();
shared_ptr<MsgType> msg;
msg.reset(msg1);
allMsgs.push(msg);
msg.reset(msg2);
allMsgs.push(msg);
MsgType* tryGetMsg = MsgType::getMsg();
cout << "[out of the method] " << tryGetMsg->getData() << endl;
}
In the MsgType::getMsg() method I can see the output, but in the main() I can't. I belive that it's trying to call MsgType::getData() which is virtual.
How can I get the MsgType outside of this method, in a way that I can access the derived class' methods?
Thanks!
The immediate fix is to just return a shared_ptr from getMsg:
shared_ptr<MsgType> MsgType::getMsg() {
shared_ptr<MsgType> msg_sp;
if (!allMsgs.empty()) {
msg_sp = allMsgs.front();
allMsgs.pop();
}
if (msg_sp) {
cout << "[in the method] " << msg_sp->getData() << endl;
}
return msg_sp;
}
and stop converting needlessly between smart and raw pointers.
The message object must be kept alive until the caller has finished using it. Since you're using shared_ptr to manage the object lifetime, you need a shared_ptr to continue existing as long as you want to use the object.
In general, mixing raw and smart pointers to the same objects is risky, because the smart pointers can only track the references they know about: that is, shared_ptr has to know everywhere a pointer to the object is being shared. It can only do this if every one of those pointers is a shared_ptr.
Note also that the easy way to diagnose object lifetime problems is to write a destructor that logs something. This brings us on to the second problem: in order for MsgType to be a suitable abstract base class here, it needs a virtual destructor.
Without that, the shared_ptr will try to destroy your object when the refcount becomes zero, but be unable (in general) to do so correctly.
class MsgType {
public:
virtual ~MsgType() {}
virtual string getData() const = 0;
};
Veering finally into code review, I intentionally omitted getMsg above.
Having a class static method to access a global queue is just weird. If you want to keep that layout, the allMsgs queue should probably be class static as well.
Instead, it's probably better to just keep a msg_queue object wherever you actually need it, with no statics or globals.
Here:
MsgType* MsgType::getMsg() {
shared_ptr<MsgType> msg_sp = nullptr;
if (allMsgs.empty()) {
msg_sp = allMsgs.front();
allMsgs.pop();
}
if (msg_sp) {
MsgType* mt = msg_sp.get();
cout << "[in the method] " << mt->getData() << endl;
return mt;
} else {
return nullptr;
}
}
When allMsgs is not empty you you copy front then pop. At that moment there is a single shared_ptr managing that object: msg_sp. Then you retrieve a raw pointer via get and return that, but when the function returns the use-count decrements to 0 and the managed object is destroyed. The returned pointer is invalid.
I find your mixing of raw and shared_ptr a little confusing. When you have a shared_ptr managing the lifetime of the object then you cannot first get a raw pointer, then let the shared_ptr destroy the managed object and still use the raw pointer. You need to properly transfer ownership when you don't want the shared pointer to destroy the managed object.
I don't know why you are mixing std::shared_ptr and C-style pointers this way, but let's ignore this and assume it's just as an exercise.
Having a look at the bottom half of your code (slightly reduced), we have this:
std::queue<std::shared_ptr<MsgType>> allMsgs;
MsgType* MsgType::getMsg();
int main() {
MsgType* msg1 = new Msg1();
std::shared_ptr<MsgType> msg;
msg.reset(msg1); // <--- 1. here, msg1 is owned by msg
allMsgs.push(msg); // <--- 2. now, msg1 is also owned by allMsgs
msg.reset(); // <--- 3. msg1 only owned by allMsgs
MsgType* tryGetMsg = MsgType::getMsg(); // <--- see below : nobody keeping msg1 alive!
std::cout << "[out of the method] " << tryGetMsg->getData() << std::endl;
}
MsgType* MsgType::getMsg() {
std::shared_ptr<MsgType> msg_sp = nullptr;
if (!allMsgs.empty()) {
msg_sp = allMsgs.front(); // <--- 4. msg1 owned by msg_sp & allMsgs
allMsgs.pop(); // <--- 5. msg1 owned by msg_sp only
}
if (msg_sp) {
MsgType* mt = msg_sp.get();
std::cout << "[in the method] " << mt->getData() << std::endl;
return mt;
} else {
return nullptr;
}
} // <--- 6. msg_sp destroyed... oh oh... msg1 dead :)
As as small addition, you can construct a shared base class pointer directly from a derived one, e.g.
auto msg_sp = std::shared_ptr<MsgType>(std::make_shared<Msg1>());

How to safely use callbacks when the bound function could be deleted

In the following code, we are creating an object, bind one function and call it before then after deleting the object.
This obviously leads to a segmentation fault as the underlying object was used after deletion.
In the context of a library providing callbacks for asynchronous data, how are we supposed to prevent callback functions to point to a nullptr?
You can test at cpp.sh/5ubbg
#include <memory>
#include <functional>
#include <iostream>
class CallbackContainer {
public:
std::string data_;
CallbackContainer(std::string data): data_(data) {}
~CallbackContainer() {}
void rawTest(const std::string& some_data);
};
void CallbackContainer::rawTest(const std::string& some_data) {
std::cout << data_ << " " << some_data << std::endl;
}
int main(int /* argc */, char const** /* argv */) {
std::unique_ptr<CallbackContainer> container;
container.reset(new CallbackContainer("Internal data"));
auto callback = std::bind(&CallbackContainer::rawTest, container.get(), std::placeholders::_1);
callback("Before");
std::cout << &callback << std::endl;
container.reset();
std::cout << &callback << std::endl;
callback("After");
return 0;
}
Returns:
> Internal data Before
> 0x7178a3bf6570
> 0x7178a3bf6570
> Error launching program (Segmentation fault)
If you can share ownership, do this:
int main(int /* argc */, char const** /* argv */) {
std::shared_ptr<CallbackContainer> container; // shared pointer
container.reset(new CallbackContainer("Internal data"));
// shared with functor
auto callback = std::bind(&CallbackContainer::rawTest, container, std::placeholders::_1);
callback("Before");
std::cout << &callback << std::endl;
container.reset();
std::cout << &callback << std::endl;
callback("After");
return 0;
}
If not, you should somehow pass invalidity to function object explicitly.
This assumes that you know when container is deleted, and manually invalidate explicitly before that:
int main(int /* argc */, char const** /* argv */) {
std::unique_ptr<CallbackContainer> container;
container.reset(new CallbackContainer("Internal data"));
std::atomic<CallbackContainer*> container_raw(container.get());
auto callback = [&container_raw] (std::string data)
{
if (auto c = container_raw.load())
c->rawTest(data);
};
callback("Before");
std::cout << &callback << std::endl;
container_raw.store(nullptr);
container.reset();
std::cout << &callback << std::endl;
callback("After");
return 0;
}
For asio cases, usually shared_from_this() is used, like std::bind(&MyClass::MyMemFunc, shared_from_this(), ptr);
The way I prefer while working with boost asio:
I faced the same issue while working with boost asio. We need to register callbacks to io_service and it was difficult to implement some sort of Manager class which manages lifetime of the objects we may create.
So, I implement something that was suggested by Michael Caisse in cppcon2016. I started passing the shared_ptr to the object to the std::bind.
I used to extend the lifetime of the object and in the callback, you can decide to either extend the lifetime of the object again (by registering the callback again) or let it die automatically.
std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>();
auto func = std::bind(&MyClass::MyMemFunc, this, ptr);
ptr.reset();
In the context of a library providing callbacks for asynchronous data, how are we supposed to prevent callback functions to point to a nullptr?
I wouldn't say that's the best solution but using by my above approach, you can detect if you need to proceed further in your callback or not.
It might not be the efficient way but it won't cause any undefined behavior.
void CallbackContainer::rawTest(const std::string& some_data, std::shared<CallbackContainer> ptr)
{
if (ptr.use_count() == 1) {
// We are the only owner of the object.
return; // and the object dies after this
}
std::cout << data_ << " " << some_data << std::endl;
}
EDIT:
An example code that shows how to do it using std::enable_shared_from_this:
#include <iostream>
#include <memory>
#include <functional>
class ABCD: public std::enable_shared_from_this<ABCD> {
public:
void call_me_anytime()
{
std::cout << "Thanks for Calling Me" << std::endl;
}
public:
ABCD(void)
{
std::cout << "CONSTRUCTOR" << std::endl;
}
~ABCD(void)
{
std::cout << "DESTRUCTOR" << std::endl;
}
};
int main(void)
{
auto ptr = std::make_shared<ABCD>();
auto cb = std::bind(&ABCD::call_me_anytime, ptr->shared_from_this());
ptr.reset();
std::cout << "RESETING SHARED_PTR" << std::endl;
std::cout << "CALLING CALLBACK" << std::endl;
cb();
std::cout << "RETURNING" << std::endl;
return 0;
}
Output:
CONSTRUCTOR
RESETING SHARED_PTR
CALLING CALLBACK
Thanks for Calling Me
RETURNING
DESTRUCTOR
As a followup, we decided to use roscpp method which is similar to Alex Guteniev's proposition.
Instead of doing std::bind explicitly, we use it internally and keep the parent as std::weak_ptr<const void> pointer to the std::shared_ptr<P> (as it would conflict with unique_ptr).
The API looks like:
std::shared_ptr<Container> container;
queue.subscribe(&Container::callback_method, container);
The subscription function is as following with T the explicit type of the data (Class-wise) but P the implicit class of the Parent class (Container in this case).
template <class P>
std::shared_ptr<ThreadedQueue<T>> subscribe(void (P::*function_pointer)(std::shared_ptr<const T>), std::shared_ptr<P> parent, size_t queue_size = -1) {
callback_ = std::bind(function_pointer, parent.get(), std::placeholders::_1);
parent_ = std::weak_ptr<const void>(parent);
}
When calling the callback, we do the following check:
if(auto lock = parent_.lock()) {
callback_(data);
}

C++: how to properly pass a variable returned by deque::front() out of a function?

I am working on a multithreading program where a "std::deque< MyObject > myBuffer" is used as a FIFO buffer, a producer thread is constantly adding custom objects to the end of a deque using push_back(), and a consumer thread uses a helper function to retrieve the object and handle the synchronization and mutex.
std::deque< MyObject > myBuffer;
std::mutex mtx;
int main() {
std::thread producerThread(producer());
std::thread consumerThread(consumer());
// other code
return 0;
}
The producer function:
void producer() {
while (somecondition) {
// code producing MyObject object
std::lock_guard<std::mutex> lck(mtx);
myBuffer.push_back(object);
}
}
The consumer function:
void consumer() {
while(somecondition) {
MyObject object1, object2;
if (retrieve(object1)) {
// process object1
}
if (retrieve(object2)) {
// process object2
}
}
}
My current helper function looks like this:
bool retrieve(MyObject & object) {
// other code ...
std::lock_guard<std::mutex> lck(mtx);
if (!myBuffer.empty()) {
object = myBuffer.front();
myBuffer.pop_front();
return true;
} else {
return false;
}
}
However, I quickly realized that deque::front() returns the reference of the first element in the container. And "object" is MyObject&, so based on my understanding, only the reference of the first element in the deque is passed to object and as a result when I call the pop_front(), the element referenced should be gone and the object variable is holding an invalid reference. Surprisingly, when I actually ran the code, everything worked as opposed to what I expected. So could anyone help me understand how this "deque::front() returns the reference" works? Thanks.
It works properly and this is expected behavior.
You don't assign the reference - you can't, C++ references are immutable. You actually copy the value. This is how it is supposed to work. Semantic of foo = ... assignment when foo is a reference is roughly:
"copy the right-hand value to the place referenced by foo".
When there is a reference on the right side, the referenced value is copied.
In your case, object = myBuffer.front(); line copies the front value of deque to variable object1 or object2 in consumer(), respectively to the call. Later call to .pop_front() destroys the value in the deque, but doesn't affect the already copied value.
i can't understand you purpose,Maybe you can try deque::at()
pop_front() removes the first element from queue. It does not delete the object. So, referencing the object after pop_front() call should work.
Update -
#include <iostream>
#include <queue>
#include <algorithm>
class newClass {
public:
newClass () {
}
~newClass () {
std::cout << " Destructor is called. " << "\n";
}
newClass(const newClass &obj) {
std::cout << "Copy is called." << "\n";
}
void print(void) {
std::cout << "Hi there !" << "\n";
}
};
void queueWithPointer(void) {
std::deque<newClass *> deque;
deque.push_back(new newClass());
deque.push_front(new newClass());
newClass *b = deque.front();
std::cout << "pop_front starts" << "\n";
deque.pop_front();
std::cout << "pop_front ends" << "\n";
b->print();
}
void queueWithObjects(void) {
std::deque<newClass> deque;
deque.push_back(newClass());
deque.push_front(newClass());
newClass ba = deque.front();
std::cout << "pop_front starts" << "\n";
deque.pop_front();
std::cout << "pop_front ends" << "\n";
ba.print();
}
int main()
{
queueWithPointer();
// queueWithObjects();
return 0;
}
Above program can be used to understand the behaviour. In case of objects, copy constructor is called and a new copy is stored in deque. When pop_front() is called, the copy is deleted. While in case of pointers, address is copied. So, the address is deleted and not the actual object referenced by the address. You will find that destructor is not called in this case.