question about smart pointers - c++

I have this snippet of the code and I must write appropriate code with class A (constructor, destructor, copy constructor, operator =), my question is do I need write smart pointers if I want that this code will work perfectly, if no, can you explain where writing smart pointers will be useful, thanks in advance
A *pa1 = new A(a2);
A const * pa2 = pa1;
A const * const pa3 = pa2;

Smart pointer are most useful when it is difficult to predict when an object should be deleted. For example: if you create an object in one point, and the object might be delete in another very distant point, or more importantly, might be deleted by several different places, smart pointers is the best solution. So basically, unless you can say for sure when an object should be deleted, and it will always be safe to do so (i.e. no other object holds a pointer to that object) use smart pointers.
Another point of view, which some friends use, is that smart pointers are so cheap (i.e. the processing cost of using them is very small), smart pointer should always be used when objects are allocated on the heap (i.e. using new). That way, you'll never have to worry about memory leakage or double-frees, etc.

A smart pointer is not needed, as non of the operations following new can throw. You just need:
A *pa1 = new A(a2);
A const * pa2 = pa1;
A const * const pa3 = pa2;
delete pa1;
If this isn't what you are asking about, please clarify your question.

Related

C++ multiple unique pointers from same raw pointer

Consider my code below. My understanding of unique pointers was that only one unique pointer can be used to reference one variable or object. In my code I have more than one unique_ptr accessing the same variable.
It's obviously not the correct way to use smart pointers i know, in that the pointer should have complete ownership from creation. But still, why is this valid and not having a compilation error? Thanks.
#include <iostream>
#include <memory>
using namespace std;
int main()
{
int val = 0;
int* valPtr = &val;
unique_ptr <int> uniquePtr1(valPtr);
unique_ptr <int> uniquePtr2(valPtr);
*uniquePtr1 = 10;
*uniquePtr2 = 20;
return 0;
}
But still, why is this valid
It is not valid! It's undefined behaviour, because the destructor of std::unique_ptr will free an object with automatic storage duration.
Practically, your program tries to destroy the int object three times. First through uniquePtr2, then through uniquePtr1, and then through val itself.
and not having a compilation error?
Because such errors are not generally detectable at compile time:
unique_ptr <int> uniquePtr1(valPtr);
unique_ptr <int> uniquePtr2(function_with_runtime_input());
In this example, function_with_runtime_input() may perform a lot of complicated runtime operations which eventually return a pointer to the same object valPtr points to.
If you use std::unique_ptr correctly, then you will almost always use std::make_unique, which prevents such errors.
Just an addition to Christian Hackl's excellent answer:
std::unique_ptr was introduced to ensure RAII for pointers; this means, in opposite to raw pointers you don't have to take care about destruction yourself anymore. The whole management of the raw pointer is done by the smart pointer. Leaks caused by a forgotten delete can not happen anymore.
If a std::unique_ptr would only allow to be created by std::make_unique, it would be absolutely safe regarding allocation and deallocation, and of course that would be also detectable during compile time.
But that's not the case: std::unique_ptr is also constructible with a raw pointer. The reason is, that being able to be constructed with a hard pointer makes a std::unique_ptr much more useful. If this would not be possible, e.g. the pointer returned by Christian Hackl's function_with_runtime_input() would not be possible to integrate into a modern RAII environment, you would have to take care of destruction yourself.
Of course the downside with this is that errors like yours can happen: To forget destruction is not possible with std::unique_ptr, but erroneous multiple destructions are always possible (and impossible to track by the compiler, as C.H. already said), if you created it with a raw pointer constructor argument. Always be aware that std::unique_ptr logically takes "ownership" of the raw pointer - what means, that no one else may delete the pointer except the one std::unique_ptr itself.
As rules of thumb it can be said:
Always create a std::unique_ptr with std::make_unique if possible.
If it needs to be constructed with a raw pointer, never touch the raw pointer after creating the std::unique_ptr with it.
Always be aware, that the std::unique_ptr takes ownership of the supplied raw pointer
Only supply raw pointers to the heap. NEVER use raw pointers which point to local
stack variables (because they will be unavoidably destroyed automatically,
like valin your example).
Create a std::unique_ptr only with raw pointers, which were created by new, if possible.
If the std::unique_ptr needs to be constructed with a raw pointer, which was created by something else than new, add a custom deleter to the std::unique_ptr, which matches the hard pointer creator. An example are image pointers in the (C based) FreeImage library, which always have to be destroyed by FreeImage_Unload()
Some examples to these rules:
// Safe
std::unique_ptr<int> p = std::make_unique<int>();
// Safe, but not advisable. No accessible raw pointer exists, but should use make_unique.
std::unique_ptr<int> p(new int());
// Handle with care. No accessible raw pointer exists, but it has to be sure
// that function_with_runtime_input() allocates the raw pointer with 'new'
std::unique_ptr<int> p( function_with_runtime_input() );
// Safe. No accessible raw pointer exists,
// the raw pointer is created by a library, and has a custom
// deleter to match the library's requirements
struct FreeImageDeleter {
void operator() (FIBITMAP* _moribund) { FreeImage_Unload(_moribund); }
};
std::unique_ptr<FIBITMAP,FreeImageDeleter> p( FreeImage_Load(...) );
// Dangerous. Your class method gets a raw pointer
// as a parameter. It can not control what happens
// with this raw pointer after the call to MyClass::setMySomething()
// - if the caller deletes it, your'e lost.
void MyClass::setMySomething( MySomething* something ) {
// m_mySomethingP is a member std::unique_ptr<Something>
m_mySomethingP = std::move( std::unique_ptr<Something>( something ));
}
// Dangerous. A raw pointer variable exists, which might be erroneously
// deleted multiple times or assigned to a std::unique_ptr multiple times.
// Don't touch iPtr after these lines!
int* iPtr = new int();
std::unique_ptr<int> p(iPtr);
// Wrong (Undefined behaviour) and a direct consequence of the dangerous declaration above.
// A raw pointer is assigned to a std::unique_ptr<int> twice, which means
// that it will be attempted to delete it twice.
// This couldn't have happened if iPtr wouldn't have existed in the first
// place, like shown in the 'safe' examples.
int* iPtr = new int();
std::unique_ptr<int> p(iPtr);
std::unique_ptr<int> p2(iPtr);
// Wrong. (Undefined behaviour)
// An unique pointer gets assigned a raw pointer to a stack variable.
// Erroneous double destruction is the consequence
int val;
int* valPtr = &val;
std::unique_ptr<int> p(valPtr);
This example of code is a bit artificial. unique_ptr is not usually initialized this way in real world code. Use std::make_unique or initialize unique_ptr without storing raw pointer in a variable:
unique_ptr <int> uniquePtr2(new int);

In Which Situations To Delete A Pointer

My following question is on memory management. I have for example an int variable not allocated dynamically in a class, let's say invar1. And I'm passing the memory address of this int to another classes constructor. That class does this:
class ex1{
ex1(int* p_intvar1)
{
ptoint = p_intvar1;
}
int* ptoint;
};
Should I delete ptoint? Because it has the address of an undynamically allocated int, I thought I don't need to delete it.
And again I declare an object to a class with new operator:
objtoclass = new ex1();
And I pass this to another class:
class ex2{
ex2(ex1* p_obj)
{
obj = p_obj;
}
ex1* obj;
};
Should I delete obj when I'm already deleting objtoclass?
Thanks!
Because it has the address of an undynamically allocated int I thought I don't need to delete it.
Correct.
Should I delete obj when I'm already deleting objtoclass?
No.
Recall that you're not actually deleting pointers; you're using pointers to delete the thing they point to. As such, if you wrote both delete obj and delete objtoclass, because both pointers point to the same object, you'd be deleting that object twice.
I would caution you that this is a very easy mistake to make with your ex2 class, in which the ownership semantics of that pointed-to object are not entirely clear. You might consider using a smart pointer implementation to remove risk.
just an appendix to the other answers
You can get rid of raw pointers and forget about memory management with the help of smart pointers (shared_ptr, unique_ptr).
The smart pointer is responsible for releasing the memory when it goes out of scope.
Here is an example:
#include <iostream>
#include <memory>
class ex1{
public:
ex1(std::shared_ptr<int> p_intvar1)
{
ptoint = p_intvar1;
std::cout << __func__ << std::endl;
}
~ex1()
{
std::cout << __func__ << std::endl;
}
private:
std::shared_ptr<int> ptoint;
};
int main()
{
std::shared_ptr<int> pi(new int(42));
std::shared_ptr<ex1> objtoclass(new ex1(pi));
/*
* when the main function returns, these smart pointers will go
* go out of scope and delete the dynamically allocated memory
*/
return 0;
}
Output:
ex1
~ex1
Should I delete obj when I'm already deleting objtoclass?
Well you could but mind that deleting the same object twice is undefined behaviour and should be avoided. This can happen for example if you have two pointers for example pointing at same object, and you delete the original object using one pointer - then you should not delete that memory using another pointer also. In your situation you might as well end up with two pointers pointing to the same object.
In general, to build a class which manages memory internally (like you do seemingly), isn't trivial and you have to account for things like rule of three, etc.
Regarding that one should delete dynamically allocated memory you are right. You should not delete memory if it was not allocated dynamically.
PS. In order to avoid complications like above you can use smart pointers.
You don't currently delete this int, or show where it's allocated. If neither object is supposed to own its parameter, I'd write
struct ex1 {
ex1(int &i_) : i(i_) {}
int &i; // reference implies no ownership
};
struct ex2 {
ex2(ex1 &e_) : e(e_) {}
ex1 &e; // reference implies no ownership
};
int i = 42;
ex1 a(i);
ex2 b(a);
If either argument is supposed to be owned by the new object, pass it as a unique_ptr. If either argument is supposed to be shared, use shared_ptr. I'd generally prefer any of these (reference or smart pointer) to raw pointers, because they give more information about your intentions.
In general, to make these decisions,
Should I delete ptoint?
is the wrong question. First consider things at a slightly higher level:
what does this int represent in your program?
who, if anyone, owns it?
how long is it supposed to live, compared to these classes that use it?
and then see how the answer falls out naturally for these examples:
this int is an I/O mapped control register.
In this case it wasn't created with new (it exists outside your whole program), and therefore you certainly shouldn't delete it. It should probably also be marked volatile, but that doesn't affect lifetime.
Maybe something outside your class mapped the address and should also unmap it, which is loosely analogous to (de)allocating it, or maybe it's simply a well-known address.
this int is a global logging level.
In this case it presumably has either static lifetime, in which case no-one owns it, it was not explicitly allocated and therefore should not be explicitly de-allocated
or, it's owned by a logger object/singleton/mock/whatever, and that object is responsible for deallocating it if necessary
this int is being explicitly given to your object to own
In this case, it's good practice to make that obvious, eg.
ex1::ex1(std::unique_ptr<int> &&p) : m_p(std::move(p)) {}
Note that making your local data member a unique_ptr or similar, also takes care of the lifetime automatically with no effort on your part.
this int is being given to your object to use, but other objects may also be using it, and it isn't obvious which order they will finish in.
Use a shared_ptr<int> instead of unique_ptr to describe this relationship. Again, the smart pointer will manage the lifetime for you.
In general, if you can encode the ownership and lifetime information in the type, you don't need to remember where to manually allocate and deallocate things. This is much clearer and safer.
If you can't encode that information in the type, you can at least be clear about your intentions: the fact that you ask about deallocation without mentioning lifetime or ownership, suggests you're working at the wrong level of abstraction.
Because it has the address of an undynamically allocated int, I
thought I don't need to delete it.
That is correct. Simply do not delete it.
The second part of your question was about dynamically allocated memory. Here you have to think a little more and make some decisions.
Lets say that your class called ex1 receives a raw pointer in its constructor for a memory that was dynamically allocated outside the class.
You, as the designer of the class, have to decide if this constructor "takes the ownership" of this pointer or not. If it does, then ex1 is responsible for deleting its memory and you should do it probably on the class destructor:
class ex1 {
public:
/**
* Warning: This constructor takes the ownership of p_intvar1,
* which means you must not delete it somewhere else.
*/
ex1(int* p_intvar1)
{
ptoint = p_intvar1;
}
~ex1()
{
delete ptoint;
}
int* ptoint;
};
However, this is generally a bad design decision. You have to root for the user of this class read the commentary on the constructor and remember to not delete the memory allocated somewhere outside class ex1.
A method (or a constructor) that receives a pointer and takes its ownership is called "sink".
Someone would use this class like:
int* myInteger = new int(1);
ex1 obj(myInteger); // sink: obj takes the ownership of myInteger
// never delete myInteger outside ex1
Another approach is to say your class ex1 does not take the ownership, and whoever allocates memory for that pointer is the responsible for deleting it. Class ex1 must not delete anything on its destructor, and it should be used like this:
int* myInteger = new int(1);
ex1 obj(myInteger);
// use obj here
delete myInteger; // remeber to delete myInteger
Again, the user of your class must read some documentation in order to know that he is the responsible for deleting the stuff.
You have to choose between these two design decisions if you do not use modern C++.
In modern C++ (C++ 11 and 14) you can make things explicit in the code (i.e., do not have to rely only on code documentation).
First, in modern C++ you avoid using raw pointers. You have to choose between two kinds of "smart pointers": unique_ptr or shared_ptr. The difference between them is about ownership.
As their names say, an unique pointer is owned by only one guy, while a shared pointer can be owned by one or more (the ownership is shared).
An unique pointer (std::unique_ptr) cannot be copied, only "moved" from one place to another. If a class has an unique pointer as attribute, it is explicit that this class has the ownership of that pointer. If a method receives an unique pointer as copy, it is explicit that it is a "sink" method (takes the ownership of the pointer).
Your class ex1 could be written like this:
class ex1 {
public:
ex1(std::unique_ptr<int> p_intvar1)
{
ptoint = std::move(p_intvar1);
}
std::unique_ptr<int> ptoint;
};
The user of this class should use it like:
auto myInteger = std::make_unique<int>(1);
ex1 obj(std::move(myInteger)); // sink
// here, myInteger is nullptr (it was moved to ex1 constructor)
If you forget to do "std::move" in the code above, the compiler will generate an error telling you that unique_ptr is not copyable.
Also note that you never have to delete memory explicitly. Smart pointers handle that for you.

Passing pointers and more

In general, I always pass pointers through functions of any objects I create; if I need something done to an object, I would pass it by pointer rather than by reference. That's just a programming habit which some might describe as miniscule; but this is where I have to ask by example:
class someObject
{
public:
someObject();
~someObject();
void do(const char* smth)
{
cout << smth << endl;
}
private:
};
class doObject
{
public:
doObject();
~doObject();
void takeObject(someObject *so)
{
pObject = so;
so->do("Hi");
}
private:
someObject *pObject;
}
And in main.cpp:
int main()
{
someObject *so = new someObject();
so->do();
doObject *do = new doObject();
do->takeObject(so);
delete so;
delete do;
}
Should memory be allocated to doObject::pObject BEFORE it is assigned the pointer parameter so of type someObject?
If pObject is assigned the foresaid parameter, should it be deleted; e.g. delete pObject?
In main.cpp someObject is deleted BEFORE doObject is. This is vital to understand because doObject has an assignment of someObject called pObject. Deleting someObject before doObject means there's a dangling pointer which implies any actions on it would produce a segmentation fault.
If I delete doObject first in main.cpp, does that also delete pObject AS WELL AS 'so' of type someObject? After all, they are linked.
If I create a new class that also a function which also requires a parameter of someObject, does that mean pObject no longer points to 'so'? Should I instead use a shared pointer so that it's possible for both classes to be able to point to 'so' and change the object as necessary?
How can the code be improved? Should I consider the use of smart pointers to ensure that I do not delete an object more than once in various parts of a program?
Yes, the question is rather complex; but that's what you get with pointers!
Should memory be allocated to doObject::pObject BEFORE it is assigned the pointer parameter so of type someObject?
Memory is allocated in main and a pointer to that memory is assigned to so. The member variable pObject will just point at the same object as so does. So memory is allocated before you assigne the member pointer variable.
If pObject is assigned the foresaid parameter, should it be deleted; e.g. delete pObject?
Someone must delete the object pointed at to not get a memory leak. Either someone does it or the ownership is shared. You decide if you transfer the ownership when you pass the pointer to another function, or not. Being consistent is the key and using smart pointers is a help.
In main.cpp someObject is deleted BEFORE doObject is. This is vital to understand because doObject has an assignment of someObject called pObject. Deleting someObject before doObject means there's a dangling pointer which implies any actions on it would produce a segmentation fault.
If you allocate dynamic memory, always deallocate in reverse allocation order to prevent dangling pointers.
If I delete doObject first in main.cpp, does that also delete pObject AS WELL AS 'so' of type someObject? After all, they are linked.
No. If the doObject destructor had done delete pObject;, then it would.
If I create a new class that also a function which also requires a parameter of someObject, does that mean pObject no longer points to 'so'? Should I instead use a shared pointer so that it's possible for both classes to be able to point to 'so' and change the object as necessary?
pObject doesn't point at so, it points at the same dynamically allocated object as so does. Any number of pointers to that object can exist in any number of classes, but it's your resonsibility to make sure that after the object is deleed, no holder of a pointer to it uses that pointer. That's why it's important to dlete objects in the correct order.
How can the code be improved? Should I consider the use of smart pointers to ensure that I do not delete an object more than once in various parts of a program?
Yes, smart pointers if you want to share the ownership (shared_ptr) or ensure there's just one owner (unique_ptr), or have the guideline that a pointer parameter is only referring to an instance, never owning.
Also use automatic instances where possible instead of dynamic.
How can the code be improved? Should I consider the use of smart pointers to ensure that I do not delete an object more than once in various parts of a program?
I'd recommend learning manual memory management first and once you've mastered it, then start using smart pointers. But of course you can jump straight into smart pointers if you think you don't need to know manual memory management.

If I define a pointer pointing to a smart pointer, does this eliminate the advantages of smart pointer?

C++ smart pointer: if in a class, I define a pointer pointing to a smart pointer, does this eliminate the advantages of smart pointer? (Note, I didn't say I want to apply this kind of usage)
Like:
class TestClass
{
public SmartPt* ptr1;
}
Here SmartPt is the smart pointer class.
Because if I do not manage the pointer well, the pointed smart pointers will not be managed too.
So does this mean it is not a good practice to use a pointer pointing to a smart pointer?
So it is better to directly use the smart pointer, like:
public SmartPt object1;
[Update 1] To not distract the reader, previously I use MySmartPt, here I replace it with SmartPt.
No, you should not try to use a pointer to a smart pointer like in the example you are sharing.
smart pointers in C++ are built around RAII principles which try to get rid of the * operator as much as possible. They also use copy/assignment overloading which raw pointers do not understand.
So if you mean doing something like this:
void * vptr;
int i = 1346;
std::shared_ptr<int> sptr = std::make_shared<int>(i);
vptr = &sptr;
Then the shared pointer will delete itself once it goes out of scope, because, that is what it is supposed to be doing. Smart pointers do not keep references of pointers to them, only references of smart pointers to their data.
Also, if you call delete vptr; one of two things will happened:
The smart pointer is going to be very mad that it had delete called.
If the smart pointer is out of scope then the vptr is pointing to an invalid block of memory.

Are std::shared_ptrs aware of each other?

That is, if I don't use the copy constructor, assignment operator, or move constructor etc.
int* number = new int();
auto ptr1 = std::shared_ptr<int>( number );
auto ptr2 = std::shared_ptr<int>( number );
Will there be two strong references?
According to the standard, use_count() returns 1 immediately after a shared_ptr is constructed from a raw pointer (ยง20.7.2.2.1/5). We can infer from this that, no, two shared_ptr objects constructed from raw pointers are not "aware" of each other, even if the raw pointers are the same.
Yes there will be two strong references, theres no global record of all shared pointers that it looks up to see if the pointer you're trying to cover is already covered by another smart pointer. (it's not impossible to make something like this yourself, but it's not something you should have to do)
The smart pointer creates it's own reference counter and in your case, there would be two separate ones keeping track of the same pointer.
So either smart pointer may delete the content without being aware of the fact that it is also held in another smart pointer.
Your code is asking for crash!
You cannot have two smart pointers pointing to the same actual object, because both will try to call its destructor and release memory when the reference counter goes to 0.
So, if you want to have two smart pointers pointing to the same object you must do:
auto ptr1 = make_shared<int>(10);
auto ptr2 = ptr1;