So one rule of thumb I've heard with respect to modern C++ style is that one shouldn't need to use new or delete, and one should instead use smart pointers. So how to go about this when I have a class where one of the members is a pointer to another object. By using a smart pointer I can avoid the need to delete, but I still need to create the object with new. E.g. is the below "canonical" modern C++ style, or how should one go about this?
#include
#include
class B {
public:
B () { std::printf("constructing B\n");}
~B () { std::printf("destroying B\n");}
};
class A {
public:
A ()
{
std::printf("constructing A\n");
b = std::unique_ptr(new B());
}
~A () { std::printf("destroying A\n");}
private:
std::unique_ptr b;
};
int main()
{
A a;
return 0;
}
You use new. There's nothing wrong with using new, it should just be used as rarely as possible.
(delete on the other hand, should almost never be used, since its usage should always be encapsulated in some sort of RAII handle like a smart pointer or a container.)
Note that when using smart pointers, you should always assign the result of new to a named smart pointer or use reset. In your case, you'd want to use:
A() : b(new B()) { }
or:
A()
{
std::unique_ptr<B> x(new B());
b = std::move(x);
}
or:
A() { b.reset(new B()); }
(For why this is important, see the "Best Practices" section of the boost::shared_ptr documentation.)
Related
I have such code:
class A
{
public:
A(void);
~A(void)
{
delete b;
delete c;
delete d;
// ...
}
private:
B* b;
C* c;
D* d;
// ...
};
//A.cpp
A(void) : b(new B()), c(new C()), d(new D()) //...
{
}
Class A takes ownership over own objects b, c, d ...
What is the best way to keep these objects? I guess, that usage of std::unique_ptr<B/C/D> type will be suitable for this way. For example, it allows to don't care about carefull writing of destructor.
it allows to don't care about carefull writing of destructor.
More than that.
Your code is not exception-safe. For example, if new D() failed by exception being thrown, delete b and delete c won't be executed and memory will leak, because destructor won't be called if constructor fails. Smart pointers can help you to avoid this kind of situation.
Holding raw pointer as members you need to implement destructor carefully, and copy constructor and assignment etc too. See What is The Rule of Three? and Rule-of-Three becomes Rule-of-Five with C++11?.
Best is to keep everything by value. If it fits*, and does not need to be hidden**. If it does not fit or needs to be hidden first preference is std::unique_ptr***, second preference (if ownership has to be shared) is std::shared_ptr. And only as a last resort (example for which I cannot even think up). You would actually have raw pointers and manage lifetime yourself, with risk of memory errors and leaks.
* - sometimes you want to be able to have parent object on stack by value and child objects are, say, large arrays which, if stored by value would overflow the stack
** - sometimes you don't want to show what child objects really are (because they are complex, say boost.fusion adapted classes. Then you would want some form of PIMPL idiom:
class.hpp
struct b;
struct A { std::unique_ptr<b> b_; A(); ~A(); }
class.cpp:
struct b { ... }
A::A() = default;
A::~A() = default;
*** - automatic management of dynamically allocated members with unique_ptr
struct A {
std::unique_ptr<b> b_;
A(...):
b_(std::make_unique<b>(...)) {}
};
I think it's worth mentioning that if you do not want to transfer ownership, you must use const std::unique_ptr. Using a non-const std:unique_ptr allows to transfer it to another std:unique_ptr.
I've stared using smart pointer and trying to wrap my head around best uses for it. I've read plenty of articles but I'm confused on which to use in the following example. I've included a shared_ptr and unique_ptrexamples to show what I'm trying to accomplish:
class A
public:
A();
private:
unique_ptr<B> ptrB;
unique_ptr<SomeObject> ptrUnique;
shared_ptr<SomeObject> ptrShared;
A::A()
{
ptrB(new B());
ptrUnique(new SomeObject());
ptrB->PassUnique(ptrUnique);
ptrShared(new SomeObject());
ptrB->PassShared(ptrShared);
}
class B:
public:
void PassUnique(unique_ptr<SomeObject> &ptr_unique);
void PassShared(weak_ptr<SomeObject> &ptr_weak);
void DoSomething();
private:
unique_ptr<SomeObject> ptrUnique;
weak_ptr<SomeObject> ptrWeak;
B::PassUnique(unique_ptr<SomeObject> &ptr_unique)
{
ptrUnique = ptr_unique;
}
B::PassShared(weak_ptr<SomeObject> &ptr_weak)
{
ptrWeak = ptr_weak;
}
B::DoSomething()
{
ptrUnique->SomeMethod();
shared_ptr<SomeObject> ptr1 = ptrWeak.lock();
ptr1->SomeMethod();
}
SomeObject class can be any class. A good example is a database handle that I pass from the parent class A were it was originally initiated to multiple class like B. And from B to C if it exists. My question is if I'm passing a unique_ptr as a reference will setting for example ptrUnqiue = ptr_unique in B:PassUnique create a copy which then is not correct? Or should this be done via shared_ptr? This understanding is what is confusing with smart pointers for me and would appreciate clarification.
Well, this is a question of lifetime. Do you need SomeObject to outlive A? Do B send or is being use outside of this context? You have to decide when your objects dies. If you think SomeObject exists only in this context, I would recommend A to be the owner, as it allocate the resource, and be to old a raw pointer to SomeObject. I would look like this:
class A
public:
A();
private:
unique_ptr<B> ptrB;
unique_ptr<SomeObject> ptrUnique;
};
A::A()
{
ptrB(new B());
ptrUnique(new SomeObject());
ptrB->PassUnique(*ptrUnique);
}
class B:
pubic:
void PassUnique(SomeObject& obj);
void DoSomething();
private:
SomeObject* ptrUnique;
};
B::PassUnique(SomeObject& obj)
{
ptrUnique = &obj;
}
B::DoSomething()
{
ptrUnique->SomeMethod();
}
There is no such thing as
ptrUnique = ptr_unique;
If you need SomeObject to be used and owned outside of this structure, then go with std::shared_ptr like you did. There were no errors with your std::shared_ptr code.
Answer is basically what would be a lifetime of the pointer in the A, B and/or C. Think of it as ranges, [A...a), [B...b) and [C...c). If [B...b) is always within [A...a) and [C...c) is always within [B...b), they have like a Russian dolls hierarchy, then passing down ref-to-ptr is ok. If ranges overlap and changes wildly so you don't really control where last ptr will be destructed and object will be deleted, you'd have to go with shared_ptr.
My code is like following, basically I am using some external library and embed some class objects from this library to myClass, then do things with OBJ,
#include "extern_lib.h" //some library
class myClass
{
public:
extern_class *obj1;
extern_class *obj2;
double arr[3];
};
int main()
{
myClass *OBJ= new myClass();
OBJ->obj1 = new extern_class(arg1...);
OBJ->obj2 = new extern_class(arg2...);
//do something like
OBJ->obj1->extern_fun1(arg1...);
OBJ->obj2->extern_fun2(arg2...);
//delete
delete OBJ;
return 0;
}
I would like to know,
1- in order to free all the objects, is it enough to delete OBJ?
2- is there better ways to write this code?
No, it is not enough. You have to call delete for every new you place in your code explicitely.
Use smart pointers like std::unique_ptr or better, use RAII. To clarify that: smart pointers and RAII are not even only better ways of doing so, they are the ways of doing it correctly in modern C++.
Here's an adequate example with RAII:
#include "extern_lib.h"
class myClass
{
public: // note that public members are possibly bad design (depending on your situation)
extern_class obj1;
extern_class obj2;
double arr[3];
};
int main()
{
myClass foo;
foo.obj1.extern_fun(arg1...);
foo.obj2.extern_fun(arg2...);
return 0;
}
Please note that it's not possible to use RAII in every situation. If you run into such, use smart pointers as stated:
#include "extern_lib.h"
class myClass
{
public: // note that public members are possibly bad design (depending on your situation)
std::unique_ptr<extern_class> obj1;
std::unique_ptr<extern_class> obj2;
double arr[3];
};
int main()
{
myClass foo;
foo.obj1 = std::unique_ptr<extern_class>(new extern_class(arg1...));
foo.obj2 = std::unique_ptr<extern_class>(new extern_class(arg2...));
foo.obj1->extern_fun(arg1...);
foo.obj2->extern_fun(arg2...);
return 0;
}
In order to free all the objects, is it enough to delete OBJ?
No, this will produce a resource leak as the (default) destructor of myClass doesn't care about deleting the pointer members.
Is there better ways to write this code?
Yes, use smart pointers. For example:
class myClass
{
public:
std::unique_ptr<extern_class> obj1;
std::unique_ptr<extern_class> obj2;
double arr[3];
};
In general, try to make resources owned by classes. That is, allocate them in the constructor and deallocate them in the destructor. The standard library's smart pointers will already do that job for you. Avoid managing more than one resource inside a single class.
By the way: If your example is not contrived and you are really not using polymorphism at all, then just get rid of all those news and simply use variables with automatic storage duration. C++ is not Java.
Update: Here is (one way of) how to get rid of new if polymorphism is not needed:
class myClass
{
public:
extern_class obj1;
extern_class obj2;
double arr[3];
myClass(type arg1a, ..., type arg2a, ...) : obj1(arg1a, ...), obj2(arg2a, ...)
// ^^^^ member initializer list ^^^^
{
}
};
The key is to create the member objects as part of the process of creating myClass by using a so-called member initializer list. If you are programming C++11, prefer writing obj1 {arg1a, ...}, obj2 {arg2a, ...} for consistency. (The old syntax still works equally well, however.)
Likewise in your main function:
int
main()
{
myClass mc(arg1a, ..., arg2a, ...); // (1)
mc.obj1.extern_func(...);
mc.obj2.extern_func(...);
return 0; // (2)
}
At line (1), we create an instance of myClass on the stack using our new constructor that will create the members obj1 and obj2 correctly. The compiler-generated default constructor of myClass will correctly destruct mc.obj1 and mc.obj2 as mc goes out of scope on line (2). Again, in C++11 line (1) can be written more cleanly as myClass mc {arg1a, ..., arg2a, ...};.
I have 2 classes, A and B.
In class A, I have a pointer on B called Bptr.
I allocate memory for Bptr in the constructor of A, and I free memory of Bptr in A's destructor.
class B {
//whatever
public:
B(int,int);
}
class A {
private:
B * Bptr;
public:
A();
}
A::A(){
Bptr = new B(2,5);
}
A::~A(){
delete Bptr;
}
How can I integrate Boost in my code and use the smart pointer : boost::shared_ptr ? How would my code look like?
Thanks a lot!
The first question to ask yourself: why do you want to dynamically allocate the object in the first place? Can you just replace the pointer with a member of type B?
Assuming there is a good reason, then why shared_ptr (rather than scoped_ptr or, in modern C++, unique_ptr)? Why do you need shared ownership?
Once you've answered these questions, and determined that shared ownership is the right solution, just replace B* with a shared pointer, initialise it in the constructor, and get rid of the redundant destructor (assuming it's not needed for anything else).
class A {
private:
boost::shared_ptr<B> Bptr;
public:
A() : Bptr(boost::make_shared<B>(2,5)) {}
};
You could simply initialise it with a pointer, Bptr(new B(2,5)), but using make_shared makes more efficient use of memory and (in more complicated situations than this) makes it easier to ensure exception safety.
class B {
//whatever
public:
B(int,int);
}
class A {
private:
boost::shared_ptr<B> Bptr;
public:
A();
}
A::A(){
Bptr = boost::make_shared<B>(2,5);
}
A::~A(){
// Bptr automatically deleted if this is the only boost::shared_ptr pointing to it
}
Although you could simply use new B(2,5) instead of boost::make_shared<B>, the latter is exception-safe.
I have't coded in c++ for some time and I got stuck when I tried to compile this simple snippet:
class A
{
public:
void f() {}
};
int main()
{
{
A a;
a.f(); // works fine
}
{
A *a = new A();
a.f(); // this doesn't
}
}
It's a pointer, so instead try:
a->f();
Basically the operator . (used to access an object's fields and methods) is used on objects and references, so:
A a;
a.f();
A& ref = a;
ref.f();
If you have a pointer type, you have to dereference it first to obtain a reference:
A* ptr = new A();
(*ptr).f();
ptr->f();
The a->b notation is usually just a shorthand for (*a).b.
A note on smart pointers
The operator-> can be overloaded, which is notably used by smart pointers. When you're using smart pointers, then you also use -> to refer to the pointed object:
auto ptr = make_unique<A>();
ptr->f();
Allow an analysis.
#include <iostream> // not #include "iostream"
using namespace std; // in this case okay, but never do that in header files
class A
{
public:
void f() { cout<<"f()\n"; }
};
int main()
{
/*
// A a; //this works
A *a = new A(); //this doesn't
a.f(); // "f has not been declared"
*/ // below
// system("pause"); <-- Don't do this. It is non-portable code. I guess your
// teacher told you this?
// Better: In your IDE there is prolly an option somewhere
// to not close the terminal/console-window.
// If you compile on a CLI, it is not needed at all.
}
As a general advice:
0) Prefer automatic variables
int a;
MyClass myInstance;
std::vector<int> myIntVector;
1) If you need data sharing on big objects down
the call hierarchy, prefer references:
void foo (std::vector<int> const &input) {...}
void bar () {
std::vector<int> something;
...
foo (something);
}
2) If you need data sharing up the call hierarchy, prefer smart-pointers
that automatically manage deletion and reference counting.
3) If you need an array, use std::vector<> instead in most cases.
std::vector<> is ought to be the one default container.
4) I've yet to find a good reason for blank pointers.
-> Hard to get right exception safe
class Foo {
Foo () : a(new int[512]), b(new int[512]) {}
~Foo() {
delete [] b;
delete [] a;
}
};
-> if the second new[] fails, Foo leaks memory, because the
destructor is never called. Avoid this easily by using
one of the standard containers, like std::vector, or
smart-pointers.
As a rule of thumb: If you need to manage memory on your own, there is generally a superiour manager or alternative available already, one that follows the RAII principle.
Summary: Instead of a.f(); it should be a->f();
In main you have defined a as a pointer to object of A, so you can access functions using the -> operator.
An alternate, but less readable way is (*a).f()
a.f() could have been used to access f(), if a was declared as:
A a;
a is a pointer. You need to use->, not .