I have a class Page which needs a Background object (in my project each page has a background). The Background is the base class of other classes (e.g. RuledBackground or DottedBackground) that specify the background in more detail. Because of this, I need polymorphism so I have to store the Background object using a pointer. However, since each Page essentially "owns" a unique Background object I thought I would use a std::unique_ptr<Background> in my Page class, so the background of each page is automatically deleted when the page is destroyed. The code below illustrates my class structure:
class Page{
public:
Background* background() {
return m_background.get();
}
private:
std::unique_ptr<Background> m_background;
};
In the code above instead of returning the unique_ptr, I am directly returning the raw pointer for the background, because it is my understanding that passing around a raw pointer is fine (or is it not?). The problem I see with my approach is to figure out how to initialize the raw pointer from outside the class, something like this
void setBackground(Background *bg){
m_background = std::make_unique<Background>(bg);
}
seems quite bad (since I suppose I will need to create the raw pointer somewhere).
The other approach I thought about is to be make the unique_ptr a public member variable and return a reference to it and then I can initialise it from outside the class.
What would be the most elegant and safest solution to what I just described? Is there a better alternative that does the same thing?
Related
Recently, I decided that it was time that I should dig into smart pointers. I read about the different kinds (unique, shared, weak), but I'm not sure about one thing.
Let say that I have a class Player and a GameMap class. The content of those classes are irrelevant for the next part. I also have an Engine class, that represents the object that will hold the main components of my game, like this:
class Engine {
public:
Engine();
~Engine();
private:
std::unique_ptr<Player> m_player;
std::unique_ptr>GameMap> m_gamemap;
};
These are the only instances of the player and game map that will be created, and the Engine owns them, and should be responsible for their allocation and deletion. So, a unique_ptr seems to be the good choice here.
Now, I would like to keep a simple reference to m_player in my GameMap class, since it would be easier for me than passing the m_player to each function that need it.
My question is: is using a raw pointer (obtained through the get() method) in the GameMap class the best way to keep a reference to the original unique_ptr located in the Engine class? I think that I can't use another unique_ptr pointing to the original one, since it would not be logical regarding to the use case of unique_ptr.
I think that using of raw pointer isn't the best way. For example, better way is use shared_ptr for player and gamemap. And adds weak_ptr of player into gamemap.
I have a class containing large member variables. In my case, the large member variable is a container of many objects and it must be private as I don't want to allow a user to modify it directly
class Example {
public:
std::vector<BigObject> get_very_big_object() const { return very_big_object; }
private:
std::vector<BigObject> very_big_object;
}
I want a user to be able to view the object without making a copy:
Example e();
auto very_big_object = e.get_very_big_object(); // Uh oh, made a copy
cout << very_big_object[11]; // Look at any element in the vector etc
I'm a bit confused about the best way to do it. I thought about returning a constant reference, i.e., make my getter:
const std::vector<BigObject>& get_very_big_object() const { return very_big_object; }
I read this article that suggests it could be risky and that that a smart pointer std::unique_ptr could be better, but that this problem can be best solved using modern C++11 move semantics. But I found that a bit cryptic.
What's the modern best practice for doing this?
I read this article that suggests it could be risky and that that a smart pointer std::unique_ptr could be better, but that this problem can be best solved using modern C++11 move semantics.
On this point, the article is flat-out wrong. A smart pointer does not remove the "risk".
Quick summary of relevant parts of the article
If a class returns a const reference to a data member, client code may introduce a const_cast and thereby change the data member without going through the class' API.
The article proposes (incorrectly) that the above can be avoided by using a smart pointer. The setup is for the class to maintain a shared pointer to the data, and have the getter return that pointer cast to a shared pointer to const data.
Critique of the points
First of all, this does not work. All one has to do is de-reference the smart pointer to get a const reference to the data, which can then be const_cast as before. Using the author's own example, instead of
std::string &evil = const_cast<std::string&>(obj.someStr());
use
std::string &evil = const_cast<std::string&>(*obj.str_ptr());
to get the same data-changing results when returning a smart pointer. The entire article is not wrong, but it does get several points wrong. This is one of them.
Second of all, this is not your concern. When you return a const reference, you are telling client code that this value is not to be changed. If the client code does so anyway, it's the client code that broke the agreement. Essentially, the client code invoked undefined behavior, so your class is free to do anything, even crash the program.
What's the modern best practice for doing this?
Simply return a const reference. (Most rules have exceptions, but in my experience, this one seems to be on target 95-99.9% of the time.)
What I did when I was working on my BDD-library for school is to create a wrapper class called VeryBigObject, which contacts the singleton upon instantiation and hides a reference-counting pointer, from there you can override the operator->() method to allow for direct access to the class's methods.
So something like this
class VeryBigObject {
private:
vector<BigObject>* obj;
public:
VeryBigObject() {
// find a way to instantiate with a pointer, not by copying
}
VeryBigObject(const VeryBigObject& o) {
// Update reference counts
obj = o.obj;
}
virtual VeryBigObject operator->(const VeryBigObject&); // I don't remember how to do this one, just google it.
... // Do other overloads as you see fit to mask working with the pointer directly.
};
This allows you to create a small portable class that you don't have to worry about copying, but also has access to the larger object easily. You'll still need to worry about things like caching and such though
I'm using box2d and as you already may know, it holds a void* to an object which i can use as reference when collisions occur between different entities. Problem is that the original item is saved inside a shared_ptr since the ownership is unknown and different classes (example player class) can 'equip' another class (weapon).
I'm just wondering if its possible to put this pointer inside a shared_ptr and refer to the same object as the original one?
This is an example:
std::vector<std::shared_ptr<Environment>> listEnvironment;
listEnvironment.push_back(std::make_shared(new Weapon()));
//takes a void pointer
box2d->userId = listEnvironment.back().get();
//some shit happens somewhere else and collision occurs and I get pointer back from box2d's callback:
Environment* envPtr = static_cast<Environment*>(box2d->userId);
As you can see envPtr is going to cause trouble.
Is there a way to refer to the old smart-pointer and increase its reference value?
PS:
In actuality every class creates an box2d body which holds a 'this' pointer so i don't actually have the address to the smart-pointer either. The example above is kind narrowed down to give you a hint of the problem i'm facing.
Best regards
nilo
If Environment has std::enable_shared_from_this<Environment> as a parent class then, yes. Just call envPtr->shared_from_this().
I have been reading up on smart pointers and recently in class my TA said that we should never use raw pointers. Now, I've done a lot of reading online and looked at different questions on this website but I'm still confused on some aspects of smart pointers. My question is: which smart pointer would I use if I want it to be used across my program? I'll show some code.
So I have a basic Application class that makes declarations of objects from class AI. Note: I have two different smart pointers, a unique one and a shared one, for testing reasons.
// Application class in Application.h
class Application
{
public:
Application(){}
~Application(){}
//... additional non-important variables and such
unique_ptr<AI> *u_AI; // AI object using a unique pointer
shared_ptr<AI> *s_AI; // AI object using a shared pointer
//... additional non-important variables and such
void init();
void update();
};
// AI class in AI.h
class AI
{
public:
AI(){}
~AI(){}
bool isGoingFirst;
};
In the Application init function, I want to create the AI object, and then I want to use it in the update function. I am not sure if I am declaring my pointer right at all, but I know for a fact that it compiles and it works for assigning and printing out data in the init function. More code below.
void Application::init()
{
//.. other initialization's.
std::shared_ptr<AI> temp(new AI());
sh_AI = &temp;
sh_AI->isGoingFirst = true;
//.. other initialization's.
// Function ends.
}
void Application::update()
{
if(sh_AI->get()->isGoingFirst == true)
{
// Do something
}
else
{
// Do something else
}
// Other code below
}
Later in my program, the update function is called, which uses the same AI smart pointer that I declared in my class Application. What I have found out is that the smart pointer AI object is being deleted. I understand that smart pointers have automatic memory management, but is there a smart pointer that will allow you to use a it in different functions without creating any major problems, such as memory leaks or dangling references? Or am I missing the whole point of smart pointers?
I'm sorry if this was answered in another question but I read into a lot of the other questions, and while I understand more about smart pointers, I'm still learning. Thank you!
As Neil Kirk pointed out in the comments, these declarations are not what you want:
unique_ptr<AI> *u_AI; // AI object using a unique pointer
shared_ptr<AI> *s_AI; // AI object using a shared pointer
u_AI and s_AI are still objects to raw pointers. The whole point is to remove the need to manage the raw pointer directly. So now you replace them with:
unique_ptr<AI> u_AI; // AI object using a unique pointer
shared_ptr<AI> s_AI; // AI object using a shared pointer
to assign your created pointer, you use the function make_unique or make_shared:
u_AI = unique_ptr<AI>(new AI()); // Yu may be able to use make_unique like
// make_shared but it's new to C++14. may not be available
s_AI = make_shared<AI>();
Then, when you need to access them, you just pretend they are pointers, so in your update function:
if(sh_AI->get()->isGoingFirst == true)
becomes:
if(sh_AI->isGoingFirst == true)
As for when to use unique_ptr vs shared_ptr, you answer that by answering the following question: What do I want to happen when someone makes a copy of Application? i.e.:
Application app1;
app1.init();
Application app2 = app1; // ?? what happens to AI object in app2?
There are 3 possible answers:
I want there to be an extra copy of AI in app2. In this case you use unique_ptr and make sure you implement a copy constructor that does the copying.
I want app2 and app1 to share a copy of AI. In this case you use shared_ptr and the default copy constructor will do the job for you.
I don't want there ever to be a copy of Application. (Which makes sense for a class called Application). In this case it doesn't really matter (in which case I would default to unique_ptr) and remove the copy constructor:
Application(const Application&) = delete;
Short answer: Since your pointer is public, I suggest you use a shared_ptr. However, your pointer does not need to be public so if it was private you could use a unique_ptr since you only use it in your own instance.
The truth is though that it does not really matter much (and I know I'll get some downvotes with this). There are two reasons to use unique_ptr:
it never leaves your module and you just need a replacement for a naked pointer
you want to explicitly show that it is not supposed to leave your module.
On the other hand if you need to ever share the pointer (even in a read-only way) then you will have to use a shared_ptr.
A lot of times it is more convenient to use shared_ptr to begin with but for reason 2) above it is worth using unique_ptr.
Not a reason to use unique_ptr: performance. All I say is make_shared.
Now to your code
This is how you define a smart pointer:
std::shared_ptr<AI> s_AI;
std::unique_ptr<AI> u_AI;
This is how you initialize it:
s_AI = std::make_shared<AI>(); // or
s_AI = std::shared_ptr<AI>(new AI);
u_AI = std::unique_ptr<AI>(new AI);
Note that there is no std::make_unique in C++11. It's going to be in C++14 and it's not that hard to write a replacement but fact is that in C++11 there is none.
This is how you use the pointers:
s_AI->isGoingFirst;
That's it, it behaves like a normal pointer. Only if you have to pass it to a function that needs a pointer you need to use .get().
here is how you delete (empty) the pointer:
s_AI.reset();
Again, I suggest you make your pointer private. If you need to pass it out make sure you use a shared_ptr and write a getter method:
std::shared_ptr<AI> getAI() const {
return s_AI;
}
Remember that if you do this you can't assume that your AI object will be destroyed when your Application object is.
I've got a function inside a class (A) that essentially takes as a parameter a pointer to another class (B). The B class is inherited by multiple other classes which it should also accept.
What I would like to do is take ownership of this pointer to store for later use in the class, it won't be used outside the class again for anything else. While I would make the parameter a shared_ptr, I would like to avoid that as much as possible due to other people I work with who don't quite get the whole smart pointer thing. Is there any way to do this?
Here's a sort of example that I would like to do, although from what I've tested this doesn't work.
//In .h file
std::vector< unique_ptr< B > > data_store;
//In .cpp file
void A::add_data(B* NewItem)
{
data_store.resize(data_store.size()+1);
data_store[data_store.size()-1] = NewItem;
}
Second to that, I would like to maybe use a copy constructor or something similar to use a smart pointer inside the class: with what I'm having to do it could get a bit ugly if I have to do manual deletes. The problem with that is that I don't know whether it's the base class (B) coming in or whether it's a class that inherited from B. I'm not too sure how to deal with that without having to hard-code in some kind of checkable ID for the class and using the correct copy/move constructors, which I would like to avoid at all costs.
I'm using an updated Clang and libC++ from llvm which I updated about 10am UK time on 12th March 2012.
For any pointer that isn't supposed to be shared, which the class has sole ownership of the std::unique_ptr<T> is the correct choice. It will automatically delete the pointer when the owning object goes out of scope/is deleted. I would actually advice against using a shared pointer for this at all, as it would communicate to other developers that this member is supposed to be shared.
So for the copying. Since you have a pointer to an object which might have subclasses you need to use the clone idiom instead of a normal copy constructor. It is normally implemented by having a virtual clone function which returns a pointer (or a smart pointer) to the class. This requires all subclasses to reimplement this, returning a copy of itself.
class Base {
...
virtual std::unique_ptr<Base> clone() const = 0;
...
};
class Subclass {
...
virtual std::unique_ptr<Base> clone() const {
return std::unique_ptr<Base>(new Subclass(*this));
}
};
If the owning object has a copy constructor it will have to invoke this clone member function on the object it owns when creating a copy of itself.
If you wish to creater object, that owns vector of pointers you should use boost::vector_ptr. It automatically deletes all objects contained in itself