I have a question about the behaviour of shared_ptr.reset().
In this scenario I have a cyclic reference with the following classes. I have a book and an owner, which both have std::shared_ptrs to each other, creating a cyclic reference.
Book.h
#pragma once
class Owner;
class Book
{
public:
Book(std::string title);
~Book();
void OutputDetails();
void SetOwner(std::shared_ptr<Owner> owner);
void OutputOwnerInformation();
private:
std::string m_title;
std::shared_ptr<Owner> m_owner; // Book hangs onto the owner and creates a circular dependency
};
Book.cpp
#include "stdafx.h"
#include <iostream>
#include "Book.h"
#include "Owner.h"
Book::Book(std::string title) : m_title(title) {}
Book::~Book() {
std::cout << "Book Destroyed" << std::endl;
}
void Book::SetOwner(std::shared_ptr<Owner> owner) {
m_owner = owner; // strong reference
}
void Book::OutputOwnerInformation() {
std::cout << "Owner is: " << m_owner->GetName() << std::endl;
}
void Book::OutputOwnerInformation() {
std::cout << "Owner is: " << m_owner->GetName() << std::endl;
}
Owner.h
#pragma once
class Book; // To avoid circular #includes
class Owner
{
public:
Owner(std::string name, std::shared_ptr<Book> book);
~Owner();
void OutputDetails();
std::string GetName();
private:
std::string m_name;
std::shared_ptr<Book> m_book; // Owner hangs onto the book
};
Owner.cpp
#include "stdafx.h"
#include "Owner.h"
#include "Book.h"
Owner::Owner(std::string name, std::shared_ptr<Book> book) : m_name(name), m_book(book) {}
Owner::~Owner() {
std::cout << "Owner Destroyed" << std::endl;
}
void Owner::OutputDetails() {
std::cout << m_name << " owns " << std::endl;
m_book->OutputDetails();
}
std::string Owner::GetName() {
return m_name;
}
Here is the main.cpp. In this case, book and owner have strong references to each other and will memory leak once _tmain exits its scope. The destructors for both book and owner are not called when I insert breakpoints in the respective destructors.
main.cpp
#include "stdafx.h"
#include <memory>
#include "Book.h"
#include "Owner.h"
int _tmain(int, _TCHAR*)
{
{
std::shared_ptr<Book> book = std::shared_ptr<Book>(new Book("Moby Dick"));
std::shared_ptr<Owner> owner = std::shared_ptr<Owner>(new Owner("George Heriot", book));
// Introduced a circular dependency so
// neither gets deleted
book->SetOwner(owner);
owner->OutputDetails();
book->OutputOwnerInformation();
}
return 0;
}
I wanted to see if I could reset() the pointers such that the destructor was called and to break the cyclic dependency. According to my understanding of shared_ptr.reset(), the object should become empty.
http://www.cplusplus.com/reference/memory/shared_ptr/reset/
However, my break points in both destructors are not being hit. My assumption would be that because I have reset both book and owner, the reference count would drop to 0 for both and they would be destroyed when _tmain returns.
main2.cpp
#include "stdafx.h"
#include <memory>
#include "Book.h"
#include "Owner.h"
int _tmain(int, _TCHAR*)
{
{
std::shared_ptr<Book> book = std::shared_ptr<Book>(new Book("Moby Dick"));
std::shared_ptr<Owner> owner = std::shared_ptr<Owner>(new Owner("George Heriot", book));
// Introduced a circular dependency so
// neither gets deleted
book->SetOwner(owner);
owner->OutputDetails();
book->OutputOwnerInformation();
owner.reset();
book.reset();
}
return 0;
}
I understand that this is already horrible code and I could use a weak_ptr to remove the cyclic dependency but I am just curious why reset() does not break this dependency.
Try printing owner.use_count() and book.use_count() before resetting them. You'll see the use counts are 2. The reset calls will make owner and book decrement their counts by 1, but there are still other shared_ptr objects that share ownership with them and which you don't reset, so the reference counts don't reach zero.
If you think about it you should realise that of course reset() can't break cycles, because the equivalent of reset() happens in the shared_ptr destructor anyway. If the destructor could break cycles like that then there would be no problem creating cycles in the first place.
Related
I am trying to create a simple program in C++ that creates lists of movies using 2 classes: Movie, which contains details of one movie, and Movies, which contains a name and a vector of Movie objects. The whole point is that the user should only interact with the class Movies, therefore I have chosen to make all the members (both data and methods) of the Movie class private.
I keep getting the following error if I let Movie::~Movie() as it is, but if I comment it in both .h and .cpp, it works just fine.
I have explicitly made Movies class a friend of Movie class, so it can access all its members.
error from Visual Studio Community 2019
Movie.h:
#pragma once
#include<iostream>
#include<string>
class Movie
{
friend class Movies;
private:
std::string name;
std::string rating;
int watchedCounter;
int userRating;
std::string userOpinion;
// methods also private because the user should only interact with the Movies class, which is a friend of class Movie
std::string get_name() const;
Movie(std::string nameVal = "Default Name", std::string ratingVal = "Default Rating", int watchedCounterVal = 0, int userRatingVal = 0, std::string userOpinionVal = "");
~Movie();
};
Movie.cpp:
#include "Movie.h"
// Name getter
std::string Movie::get_name() const
{
return this->name;
}
///*
// Destructor
Movie::~Movie()
{
std::cout << "Movie destructor called for: " << this->name << std::endl;
}
//*/
// Constructor
Movie::Movie(std::string nameVal, std::string ratingVal, int watchedCounterVal, int userRatingVal, std::string userOpinionVal) : name{ nameVal }, rating{ ratingVal }, watchedCounter{ watchedCounterVal }, userRating{ userRatingVal }, userOpinion{userOpinionVal}
{
std::cout << "Movie constructor called for: " << name << std::endl;
}
Movies.h:
#pragma once
#include<iostream>
#include<vector>
#include "Movie.h"
class Movies
{
private:
std::string listName;
std::vector<Movie> vectOfMovies;
static int listNumber;
public:
Movies(std::string listNameVal = "Default User's Movie List ");
~Movies();
std::string get_listName() const;
void addMovie(Movie m);
};
Movies.cpp:
#include<string>
#include "Movies.h"
int Movies::listNumber = 0;
// Constructor
Movies::Movies(std::string listNameVal) : listName{listNameVal}
{
++listNumber;
listName += std::to_string(listNumber);
std::cout << "MovieS constructor called for: " << listName << std::endl;
}
// Destructor
Movies::~Movies()
{
std::cout << "MovieS destructor called for: " << listName << std::endl;
}
std::string Movies::get_listName() const
{
return this->listName;
}
//Add movie to list of movies
void Movies::addMovie(Movie m)
{
this->vectOfMovies.push_back(m);
}
And the main .cpp file:
#include <iostream>
// #include "Movie.h"
#include "Movies.h"
int main()
{
Movies moviesObj;
moviesObj.get_listName();
return 0;
}
If the constructor/destructor is declared as private, then the class cannot be instantiated. If the destructor is private, then the object can only be deleted from inside the class as well. Also, it prevents the class from being inherited (or at least, prevent the inherited class from being instantiated/destroyed at all).
The use of having destructor as private:
Any time you want some other class to be responsible for the life cycle of your class' objects, or you have reason to prevent the destruction of an object, you can make the destructor private.
For instance, if you're doing some sort of reference counting thing, you can have the object (or manager that has been "friend"ed) responsible for counting the number of references to itself and delete it when the number hits zero. A private dtor would prevent anybody else from deleting it when there were still references to it.
For another instance, what if you have an object that has a manager (or itself) that may destroy it or may decline to destroy it depending on other conditions in the program, such as a database connection being open or a file being written. You could have a "request_delete" method in the class or the manager that will check that condition and it will either delete or decline, and return a status telling you what it did. That's far more flexible that just calling "delete".
So, I suggest that you could declare ~Movie(); as public. Then, the problem will be solved.
I am learning C++ from the book called "Beginning C++ through Game Programming" and this problem showed up. The following code was originally 1 file, but I had to divide it into multiple classes.
Now, I am stuck at inheritance problem. I watched videos, read tutorials about it but nothing seemed to help. The book doesn't help either. I need to add the following attributes:
Use the multiple file class version (I am using it)
From a critter base class -- add at least 2 inheritance critters
The base class should have at least 2 attributes (data)
The inherited class should have at least 2 additional traits different from the base class and the other inherited class
Add the appropriate functions for all the attributes -- both base and inherited
Add appropriate menu items
Any help here would be highly appreciated!
critter.h
#pragma once
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Critter
{
public:
Critter(const string& name = "");
string GetName() const;
private:
string m_Name;
};
critterImp.cpp
#include <critter.h>
Critter::Critter(const string& name):
m_Name(name)
{}
inline string Critter::GetName() const
{
return m_Name;
}
farm.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
class Critter;
class Farm
{
public:
Farm(int spaces = 1);
void Add(const Critter& aCritter);
void RollCall() const;
private:
vector<Critter> m_Critters;
};
farmImp.cpp
#include <farm.h>
#include <critter.h>
Farm::Farm(int spaces)
{
m_Critters.reserve(spaces);
}
void Farm::Add(const Critter& aCritter)
{
m_Critters.push_back(aCritter);
}
void Farm::RollCall() const
{
for (vector<Critter>::const_iterator iter = m_Critters.begin();
iter != m_Critters.end();
++iter)
{
cout << iter->GetName() << " here.\n";
}
}
critFarmTest.cpp
#include <farm.h>
#include <critter.h>
int main()
{
Critter crit("Poochie");
cout << "My critter's name is " << crit.GetName() << endl;
cout << "\nCreating critter farm.\n";
Farm myFarm(3);
cout << "\nAdding three critters to the farm.\n";
myFarm.Add(Critter("Moe"));
myFarm.Add(Critter("Larry"));
myFarm.Add(Critter("Curly"));
cout << "\nCalling Roll...\n";
myFarm.RollCall();
return 0;
}
I have a problem with polymorphism in a C++ project I'm working on. I have a base class named State, and a derived TestState class. I'm trying to call a virtual function overidden in the derived class from a State pointer. The virtual function is called, but when deleting the pointer I get the following error:
Invalid address specified to RtlValidateHeap( 00FF0000, 0018FD74 )
After searching for other answers I've been able to understand that this means that the heap is corrupted, but none of the solutions I've found have worked for me.
This is the code I'm running:
int main()
{
TestState test;
State *state = new State();
state = &test;
state->Init();
delete state;
}
State.h
#pragma once
#include <iostream>
class State
{
public:
State();
virtual ~State();
virtual void Init();
virtual void Reinit();
virtual void Deinit();
};
State.cpp
#include "State.h"
State::State()
{
}
State::~State()
{
std::cout << "Destroying State!" << std::endl;
}
void State::Init()
{
std::cout << "Initialized State!" << std::endl;
}
void State::Deinit()
{
}
void State::Reinit()
{
}
TestState.h
#pragma once
#include "State.h"
#include <iostream>
class TestState : public State
{
public:
TestState();
~TestState();
void Init();
void Deinit();
void Reinit();
};
TestState.cpp
#include "TestState.h"
TestState::TestState()
{
}
TestState::~TestState()
{
std::cout << "Destroying TestState!" << std::endl;
}
void TestState::Init()
{
std::cout << "Initialized TestState!" << std::endl;
}
void TestState::Deinit()
{
}
void TestState::Reinit()
{
}
The destructor of both State and TestState are called when the pointer is deleted.
Thanks in advance.
Because you are deleting something in the stack. When you assign the pointer to a reference to a local variable you assign the pointer to an entity allocated in the stack. It cannot be delete using "delete" which is for heap variables. In addition you are leaking what you allocated with the new.
TestState test;
State *state = new State();
state = &test; //Now it points to the test which is in the stack
state->Init();
delete state; //Delete something in the stack. Not good.
Something like this should work better.
TestState test;
State *state = &test;
state->Init();
Even though the solution to your specific problem was easy (i.e. you were trying to delete a stack-allocated variable as if it was heap-allocated), I wanted to post my solution to my mysterious RtlValidateHeap assertion.
It turns out that the code I was working on had mixed settings between projects for "Runtime library" (in the project properties, under C/C++ -> Code Generation). The application has "Multithreaded Debug", the DLLs had "Multithreaded Debug DLL". They all need to be set to the same thing.
If you mix DLL and non-DLL runtime libraries, you end up with two separate heaps, and it becomes impossible to delete an object allocated under one runtime-library from code using another runtime-library. You end up with mysterious RtlValidateHeap assertions.
Hope this helps someone else.
This is what shared pointers are for :) There is a very good Smart Pointer video by The Cherno on youtube.
This should fix things change your main to this:
#include "TestState.h"
#include "State.h"
#include <memory>
int main()
{
{
std::shared_ptr<TestState> test = std::make_shared<TestState>();
std::shared_ptr<TestState> state = test;
state->Init();
}
//delete state;
}
I'm trying to figure out how queues work in C++ and am getting stuck when dealing with objects. I seem to only be able to get a return address instead of the name of the object (which is what I really want). It's also showing an error when I try to pop the element from the queue. My code is as follows:
Buyer.h file
#ifndef BUYER_H
#define BUYER_H
#include <string>
#include <queue>
#include "Order.h"
#include "Entity.h"
#include "Seller.h"
class Order;
class Seller;
class Buyer : public Entity {
public:
Buyer(const std::string &, const std::string &, double);
virtual ~Buyer() { }; // when step is added make this virtual
void addSeller(Seller *);
std::queue<Seller*> getSellers() const;
void addOrder(Order *);
std::queue<Order*> getOrders() const;
virtual void list() const override;
virtual void step() const override;
private:
std::queue<Order*> orders;
std::queue<Seller*> sellers;
};
#endif
Buyer.cpp file
#include <iostream>
#include <ostream>
#include <stdexcept>
#include <string>
#include <queue>
#include "Buyer.h"
#include "Seller.h"
#include "Order.h"
#include "Entity.h"
using namespace std;
Buyer::Buyer(const std::string &name, const std::string &id, double balance)
: Entity(name, id, balance)
{
// initialize seller and order queue??
} // Constructor
void Buyer::addSeller(Seller *s) {
sellers.push(s);
} // addSeller
std::queue<Seller*> Buyer::getSellers() const {
while(!sellers.empty()) {
return sellers;
} // while
} // getSellers
void Buyer::addOrder(Order *o) {
orders.push(o);
} // addOrder
std::queue<Order*> Buyer::getOrders() const {
while(!orders.empty()) {
return orders;
} // while
} // getOrders
void Buyer::list() const {
Entity::list();
std::cout << "Orders:\nOrder contains:";
std::cout << "\nSellers:\n";
int i = 0;
while(!sellers.empty()) {
std::cout << sellers.front() << "\n";
sellers.pop();
} // while
} //list
void Buyer::step() const {
std::cout << "\nstep enter\n"
<< "step exit\n\n";
} // step
Any help is appreciated! Thank you!
(This isn't a full answer but it is too big to go in a comment)
It's OK to return std::queue<Order *>, and so on. However, you need to be clear on who owns the objects being pointed to; i.e. who is responsible for deleting them.
When you return a std::queue<Order *>, what happens is that the returned queue is a copy of the original one, however all the pointers point to the same object that the original one pointed to . (This is a sort of "shallow copy").
If you then delete anything in the returned queue, you will cause the original queue to malfunction because it will be accessing deleted memory.
As such, this is a fragile design because the caller can easily cause the object to screw up despite the fact that getOrders is a const function.
One "solution" is to make the containers contain shared_ptr<Order> instead of Order *. Then everything happens automatically; the caller can add or delete to his heart's content.
If it is not strictly necessary for the containers to contain pointers, consider using containers of objects: std::queue<Order>. The benefit of this approach is that the default copy and move semantics are all correct.
Another approach to consider is having getOrders() and getSellers() return a const reference, instead of returning a copy of the queue.
NB. In Buyer::getSellers(), and getOrders() if it is empty then you fall off the end of the function without returning, causing undefined behaviour. You need to either return something (what's wrong with returning an empty queue?) or throw an exception.
Inside FileTwo.h
#include"iostream"
using namespace std ;
class FileTwo{
public:
FileTwo(){
cout<<"constructor for";//Here want to show the object for which the constructor has been called
}
~Filetwo(){
cout<<"Destructor for ";//Here want to show the object for which the destructor has been called
};
Inside main.cpp
#include"Filetwo.h"
int main(){
FileTwo two ;
return 0;
}
I know this sample program is very small , so we can able to find out the object for which the constructor and destructor has been called . But for big project is there any way to know the object name ? Thanks in advance .
It is possible. If your compile supports __PRETTY_FUNCTION__ or __func__ (see this), then you can do this:
#include <iostream>
using namespace std;
class FileTwo{
public:
FileTwo(){
cerr<<"constructor for "<< __PRETTY_FUNCTION__ <<" at "<<&(*this)<<endl;
}
~FileTwo(){
cerr<<"Destructor for "<< __PRETTY_FUNCTION__ <<" at "<<&(*this)<<endl;
}
};
int main(){
FileTwo two;
return 0;
}
Note that I've also printed to cerr to ensure that this output gets flushed immediately and isn't lost if the program crashes. Also, since each object has a unique *this pointer, we can use that to see when particular objects are being made or getting killed.
The output for the above program on my computer is:
constructor for FileTwo::FileTwo() at 0x7fff641cde40
Destructor for FileTwo::FileTwo() at 0x7fff641cde40
Note that __func__ is a C99 standard identifier. C++0x adds support in the form of an "implementation-defined string".
__FUNCTION__ is a pre-standard extension supported by some compilers, including Visual C++ (see documentation) and gcc (see documentation).
__PRETTY_FUNCION__ is a gcc extension, which does the same sort of stuff, but prettier.
This question has more information on these identifiers.
Depending on your compiler, this may return the name of the class, though it may be a little mangled.
#include <iostream>
#include <typeinfo>
using namespace std;
class FileTwo{
public:
FileTwo(){
cerr<<"constructor for "<< typeid(*this).name() <<" at "<<&(*this)<<endl;
}
~FileTwo(){
cerr<<"Destructor for "<< typeid(*this).name() <<" at "<<&(*this)<<endl;
}
};
int main(){
FileTwo two;
return 0;
}
If you are trying to get the name of the variable to which the class is instantiated (two in your case), then there is not, to my knowledge, a way to do this. The following will emulate it:
#include <iostream>
#include <string>
using namespace std;
class FileTwo{
public:
FileTwo(const std::string &myName) : myName(myName) {
cerr<<"constructor for "<< myName <<" at "<<&(*this)<<endl;
}
~FileTwo(){
cerr<<"Destructor for "<< myName <<" at "<<&(*this)<<endl;
}
private:
std::string myName;
};
int main(){
FileTwo two("two");
return 0;
}
Unless you name the object, it is not possible. Something like this :
#include <iostream>
#include <string>
using namespace std;
class FileTwo {
public:
FileTwo(const std::string &myName) : name(myName){
cout<<"constructor for" << name;//Here want to show the object for which the constructor has been called
}
~Filetwo(){
cout<<"Destructor for " << name;//Here want to show the object for which the destructor has been called
}
private:
std::string name;
};
and then change the main into :
#include"Filetwo.h"
int main(){
FileTwo two("two 11");
}
It is not possible to name the object,all what you can do is making a private variable to hold the name.
using namespace std;
class myClass
{
private:
string className;
public:
~myClass()
{
cout<<this->className;
}
};
you can create setters and getters for you variable.
void SetName(string name)
{
this->className = name;
}
string GetName()
{
return this->className;
}