To allocate dynamic memory, I have been using vectors all this time in C++.
But recently, while reading some source code, I found the use of "new int[size]" and on some research, found that it too allocates dynamic memory.
Can anyone give me advice as to which is better? I am looking from an algorithmic and ICPC point of view?
Always prefer the standard containers. They have well-defined copying semantics, are exception safe, and release properly.
When you allocate manually, you must guarantee that the release code is executed, and as members, you must write correct copy assignment and copy constructor which does the right thing without leaking in case of exception.
Manual:
int *i = 0, *y = 0;
try {
i = new int [64];
y = new int [64];
} catch (...) {
delete [] y;
delete [] i;
}
If we want our variables to have only the scope they really need, it gets smelly:
int *i = 0, *y = 0;
try {
i = new int [64];
y = new int [64];
// code that uses i and y
int *p;
try {
p = new int [64];
// code that uses p, i, y
} catch(...) {}
delete [] p;
} catch (...) {}
delete [] y;
delete [] i;
Or just:
std::vector<int> i(64), y(64);
{
std::vector<int> p(64);
}
It is a horror to implement that for a class that has copy semantics. Copying may throw, allocation may throw, and we want transaction semantics, ideally. An example would burst this answer tho.
Ok here.
Copyable class - Manual resource management vs containers
We have this innocent looking class. As it turns out, it is pretty evil. I feel reminded of American McGee's Alice:
class Foo {
public:
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
private:
Bar *b_;
Frob *f_;
};
Leaks. Most beginner C++ programmers recognize that there's missing deletes. Add them:
class Foo {
public:
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
~Foo() { delete f_; delete b_; }
private:
Bar *b_;
Frob *f_;
};
Undefined behavior. Intermediate C++ programmers recognize that the wrong delete-operator is used. Fix this:
class Foo {
public:
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
~Foo() { delete [] f_; delete [] b_; }
private:
Bar *b_;
Frob *f_;
};
Bad design, leaks and double deletes lurk there if the class is copied. The copying itself is fine, the compiler cleanly copies the pointers for us. But the compiler won't emit code to create copies of the arrays.
Slightly more experienced C++ programmers recognize that the Rule of Three was not respected, which says that if you have explicitly written any of destructor, copy assignment or copy constructor, you probably also need to write out the others, or make them private without implementation:
class Foo {
public:
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
~Foo() { delete [] f_; delete [] b_; }
Foo (Foo const &f) : b_(new Bar[64]), f_(new Frob[64])
{
*this = f;
}
Foo& operator= (Foo const& rhs) {
std::copy (rhs.b_, rhs.b_+64, b_);
std::copy (rhs.f_, rhs.f_+64, f_);
return *this;
}
private:
Bar *b_;
Frob *f_;
};
Correct. ... Provided you can guarantee to never run out of memory and that neither Bar, nor Frob can fail on copying. Fun starts in next section.
The wonderland of writing exception safe code.
Construction
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
Q: What happens if the initialization of f_ fails?
A: All Frobs that have been constructed are destroyed. Imagine 20 Frob were constructed, the 21st will fail. Than, in LIFO order, the first 20 Frob will be correctly destroyed.
That's it. Means: You have 64 zombie Bars now. The Foos object itself never comes to life, its destructor will therefore not be called.
How to make this exception safe?
A constructor should always succeed completely or fail completely. It shouldn't be half-live or half-dead. Solution:
Foo() : b_(0), f_(0)
{
try {
b_ = new Bar[64];
f_ = new Frob[64];
} catch (std::exception &e) {
delete [] f_; // Note: it is safe to delete null-pointers -> nothing happens
delete [] b_;
throw; // don't forget to abort this object, do not let it come to life
}
}
Copying
Remember our definitions for copying:
Foo (Foo const &f) : b_(new Bar[64]), f_(new Frob[64]) {
*this = f;
}
Foo& operator= (Foo const& rhs) {
std::copy (rhs.b_, rhs.b_+64, b_);
std::copy (rhs.f_, rhs.f_+64, f_);
return *this;
}
Q: What happens if any copy fails? Maybe Bar will have to copy heavy resources under the hood. It can fail, it will.
A: At the time-point of exception, all objects copied so far will remain like that.
This means that our Foo is now in inconsistent and unpredictable state. To give it transaction semantics, we need to build up the new state fully or not at all, and then use operations that cannot throw to implant the new state in our Foo. Finally, we need to clean up the interim state.
The solution is to use the copy and swap idiom (http://gotw.ca/gotw/059.htm).
First, we refine our copy constructor:
Foo (Foo const &f) : f_(0), b_(0) {
try {
b_ = new Bar[64];
f_ = new Frob[64];
std::copy (rhs.b_, rhs.b_+64, b_); // if this throws, all commited copies will be thrown away
std::copy (rhs.f_, rhs.f_+64, f_);
} catch (std::exception &e) {
delete [] f_; // Note: it is safe to delete null-pointers -> nothing happens
delete [] b_;
throw; // don't forget to abort this object, do not let it come to life
}
}
Then, we define a non-throwing swap function
class Foo {
public:
friend void swap (Foo &, Foo &);
};
void swap (Foo &lhs, Foo &rhs) {
std::swap (lhs.f_, rhs.f_);
std::swap (lhs.b_, rhs.b_);
}
Now we can use our new exception safe copy-constructor and exception-safe swap-function to write an exception-safe copy-assignment-operator:
Foo& operator= (Foo const &rhs) {
Foo tmp (rhs); // if this throws, everything is released and exception is propagated
swap (tmp, *this); // cannot throw
return *this; // cannot throw
} // Foo::~Foo() is executed
What happened? At first, we build up new storage and copy rhs' into it. This may throw, but if it does, our state is not altered and the object remains valid.
Then, we exchange our guts with the temporary's guts. The temporary gets what is not needed anymore, and releases that stuff at the end of scope. We effectively used tmp as a garbage can, and properly choose RAII as the garbage collection service.
You may want to look at http://gotw.ca/gotw/059.htm or read Exceptional C++ for more details on this technique and on writing exception safe code.
Putting it together
Summary of what can't throw or is not allowed to throw:
copying primitive types never throws
destructors are not allowed to throw (because otherwise, exception safe code would not be possible at all)
swap functions shall not throw** (and C++ programmers as well as the whole standard library expect it to not throw)
And here is finally our carefully crafted, exception safe, corrected version of Foo:
class Foo {
public:
Foo() : b_(0), f_(0)
{
try {
b_ = new Bar[64];
f_ = new Frob[64];
} catch (std::exception &e) {
delete [] f_; // Note: it is safe to delete null-pointers -> nothing happens
delete [] b_;
throw; // don't forget to abort this object, do not let it come to life
}
}
Foo (Foo const &f) : f_(0), b_(0)
{
try {
b_ = new Bar[64];
f_ = new Frob[64];
std::copy (rhs.b_, rhs.b_+64, b_);
std::copy (rhs.f_, rhs.f_+64, f_);
} catch (std::exception &e) {
delete [] f_;
delete [] b_;
throw;
}
}
~Foo()
{
delete [] f_;
delete [] b_;
}
Foo& operator= (Foo const &rhs)
{
Foo tmp (rhs); // if this throws, everything is released and exception is propagated
swap (tmp, *this); // cannot throw
return *this; // cannot throw
} // Foo::~Foo() is executed
friend void swap (Foo &, Foo &);
private:
Bar *b_;
Frob *f_;
};
void swap (Foo &lhs, Foo &rhs) {
std::swap (lhs.f_, rhs.f_);
std::swap (lhs.b_, rhs.b_);
}
Compare that to our initial, innocent looking code that is evil to the bones:
class Foo {
public:
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
private:
Bar *b_;
Frob *f_;
};
You better don't add more variables to it. Sooner or later, you will forget to add proper code at some place, and your whole class becomes ill.
Or make it non-copyable.
class Foo {
public:
Foo() : b_(new Bar[64]), f_(new Frob[64]) {}
Foo (Foo const &) = delete;
Foo& operator= (Foo const &) = delete;
private:
Bar *b_;
Frob *f_;
};
For some classes this makes sense (streams, for an instance; to share streams, be explicit with std::shared_ptr), but for many, it does not.
The real solution.
class Foo {
public:
Foo() : b_(64), f_(64) {}
private:
std::vector<Bar> b_;
std::vector<Frob> f_;
};
This class has clean copying semantics, is exception safe (remember: being exception safe does not mean to not throw, but rather to not leak and possibly have transaction semantics), and does not leak.
In just about any situation, std::vector is preferable. It has a destructor to free the memory, whereas manually managed memory must be explicitly deleted once you've finished with it. It is very easy to introduce memory leaks, for example if something throws an exception before it is deleted. For example:
void leaky() {
int * stuff = new int[10000000];
do_something_with(stuff);
delete [] stuff; // ONLY happens if the function returns
}
void noleak() {
std::vector<int> stuff(10000000);
do_something_with(stuff);
} // Destructor called whether the function returns or throws
It is also more convenient if you need to resize or copy the array.
The only reason to prefer a raw array is if you have extreme performance or memory limitations. vector is a larger object than a pointer (containing size and capacity information); and it will sometimes value-initialise its objects, while a raw array will default-initialise them (which, for trivial types, means they are left uninitialised).
In the rare cases when these issues might be important, you should consider std::unique_ptr<int[]>; it has a destructor which will prevent memory leaks, and has no run-time overhead when compared to a raw array.
I don't think that there's ever a case where new int[size] is preferable. You'll sometimes see it in pre-standard code, but even then, I don't think it was ever a good solution; in pre-standard days, if you didn't have an equivalent to std::vector in your tool kit, you wrote one. The only reasons you might want to use a new int[size] is in the implementation of a pre-standard vector class. (My own separated allocation and initialization, like the containers in the standard library, but this might be overkill for a very simple vector class.)
Even though both methods allocates dynamic memory, one is an object made for handling data of arbitrary length (std::vector<T>), while the other is just a pointer to a sequential line of memory slots of size N (ints in this case).
Among other differences
A std::vector<T> will automatically resize the allocated memory for your data if you try to append a new value and it runs out of space. A int * will not.
A std::vector<T> will free the allocated memory when the vector goes out of scope, a int * will not.
A int * will have little to no overhead (compared to the vector), though std::vector<T> isn't exactly a new thing and is normally very optimized. Your bottle neck will probably be elsewhere.
But a std::vector<int> will always consume more memory than a int *, and some operations will always take a little more time.
So if there are memory/CPU limitations and you want to shave off every single cycle that you possible can.. use an int *.
There are situations where one is definitely preferable over the other!
When you need "raw"/"real" memory and full control over it, operator new is your best bet.
For example when you are using placement new.
by raw/real memory I mean something that is not managed through a wrapper-container, such as std::vector<T>.
When you are looking for a container to handle arbitrary and don't want to reinvent the wheel regarding memory management; std::vector<T> (or any other appropriate STL container)
Can anyone give me advice as to which is better?
Vector is better when
You haven't learned to do manual memory management.
You have learned of it, but aren't confident yet.
You think you know how to do it, but are unwittingly overconfident.
You really know what you're doing, but might make a mistake.
You are a guru and none of the above applies, but your code might be later maintained by a colleague, for whom any of the above does apply.
...
Pretty much always.
Manual memory management can easily and often does lead to memory leaks, and worse yet, undefined behaviour.
Internally the vector do exactly the same also it will make care about the memory release. So there is no any reason to use the new operator. std::vector is a part of c++, it is standard, it is tested and it is safe, don't use the raw pointer when you have some standard way to do your work.
If you need a dynamically sized sequence of objects, use a vector. If you need to allocate raw memory and manage that memory yourself, allocate memory. You will find that sometimes vectors are more useful, and at other times a flat memory buffer is better.
Related
Note that the basis of the question is to use two malloc()s...while suggesting not using malloc() at all is perfectly valid and leads to better design, this is not the point of the question. Perhaps you can think that my client is a psychopath and I am paid to have two malloc()s.
===== Here comes the question itself =====
Say I am stuck with the following class and cannot switch to features such as vector<int>, unique_ptr<int>, etc, while not "modern", it should still work without leaking any memory, whether or not malloc() succeeds:
class Foo {
private:
int *ptr;
public:
Foo () {
this->ptr = (int*)malloc(sizeof(int) * ARR_SIZE);
if (this->ptr == NULL) {
std::bad_alloc exception;
throw exception;
}
}
~Foo () {
free(this->ptr);
}
};
The question appears if I need to malloc() twice within the same constructor:
class Foo {
private:
int *ptr0;
int *ptr1;
public:
Foo () {
this->ptr0 = (int*)malloc(sizeof(int) * ARR_SIZE_0);
if (this->ptr0 == NULL) {
std::bad_alloc exception;
throw exception;
}
this->ptr1= (int*)malloc(sizeof(int) * ARR_SIZE_1);
if (this->ptr1== NULL) {
free(this->ptr0); // QUESTION: Is this needed and does it follow the best practice?
std::bad_alloc exception;
throw exception;
}
}
~Foo () {
free(this->ptr0);
free(this->ptr1);
}
};
I am aware that it could be more advisable in the 2nd case that we create two classes which wrap one pointer each, so the principle of RAII can be thoroughly followed and the above kind of "C-style" free() in constructor is not needed.
The question is, say, for whatever reason, I must have two malloc()s in the constructor, is my design good enough (i.e., not leaking memory and not too verbose)?
Here is a RAII-enabled version.
struct Free
{
void operator()(void* p) const { std::free(p); }
};
template <typename T, typename Deleter = Free>
std::unique_ptr<T, Deleter> raii_malloc()
{
T* obj = static_cast<T*>(std::malloc(sizeof(T)));
if (obj == nullptr) throw std::bad_alloc();
return std::unique_ptr<T, Deleter>(obj);
}
template <typename T, typename Deleter = Free>
std::unique_ptr<T[], Deleter> raii_malloc_array(size_t size)
{
T* obj = static_cast<T*>(std::malloc(sizeof(T) * size));
if (obj == nullptr) throw std::bad_alloc();
return std::unique_ptr<T[], Deleter>(obj);
}
template <typename T>
using fptr = std::unique_ptr<T, Free>;
Now your class looks like this:
class Foo
{
fptr<int[]> ptr0;
fptr<int[]> ptr1;
public:
Foo() : ptr0{raii_malloc_array<int>(ARR_SIZE_0)},
ptr1{raii_malloc_array<int>(ARR_SIZE_1)}
{}
// no destructor needed
};
Note that this version is non-copyable. If you need copying, add a custom copy constructor and/or assignment operator (still no destructor needed).
You can use this with C objects that contain internal pointers or other resources that need to be freed, you just need to supply a different deleter instead of Free.
If unique_ptr is not available, it is extremely easy to roll your own simplified version.
Use std::vector or std::unique_ptr to help manage memory.
Don't use malloc unless you must.
Make sure your class is either safe to copy/move, or not copyable/movable (i.e., deleted constructor, operator=).
Think about how likely you are to handle an out-of-memory case anyway (are you going to open a file and log it while you're out of system memory?), and perhaps just terminate if the allocation fails.
A rather simple way to avoid the issue would be to allocate the necessary memory for your member variables in one go.
class Foo
{
public:
Foo()
{
ptr0 = new int[ARR_SIZE0 + ARR_SIZE1];
ptr1 = ptr0 + ARR_SIZE0;
}
~Foo()
{
delete ptr0[];
}
// PLEASE insert the rest of the
// necessary constructors
// and assignment operators...
private:
int * ptr0;
int * ptr1;
};
Using new instead of malloc here because, if you have to do manual allocations, at least do them using the C++ construct.
Your updated question makes it clearer what the question is about. I feel my first answer still holds value, but this one goes in another direction entirely, which is why I wrote it as a separate answer.
It boils down to:
If I am about to throw an exception from a constructor, do I have to actively release resources previously allocated manually in that constructor?
Yes, you do, for any resources that you would likewise have to free / close / disconnect / ... in the destructor.
If a constructor fails (i.e., throws), the object is not constructed. It is, therefore, not destructed either -- its destructor will never be called. You would lose access to ptr0 and ptr1. Your exception might be caught, the program might continue -- but you would have leaked the memory.
So, again, yes, please do release any resource you would release in the destructor that you already allocated in the constructor before throwing the exception.
All the other comments and remarks also hold true, though. You should strive not to mix C constructs and C++ constructs. Writing idiomatic C++ instead of what is disparagingly called "C with classes" will result in better readable, more stable and likely more efficient code.
Does the code below produce a memory leak?
#include <utility>
#include <stdexcept>
struct A {};
struct B {
B() {
throw std::runtime_error("");
}
};
template <class T>
class MyPtr {
public:
MyPtr(T* p) : m_p(p) {}
MyPtr(MyPtr&& other) : m_p(other.m_p) {
other.m_p = nullptr;
}
~MyPtr() {
delete m_p;
}
private:
T* m_p;
};
class Foo {
public:
Foo(MyPtr<A> a, MyPtr<B> b) : m_a(std::move(a)), m_b(std::move(b)) {}
private:
MyPtr<A> m_a;
MyPtr<B> m_b;
};
int main() {
try {
Foo foo(new A(), new B());
}
catch (const std::exception&) {
}
return 0;
}
Is there a difference between
Foo foo(new A(), new B());
and
Foo foo(MyPtr(new A()), MyPtr(new B()));
?
The evaluation order is based on sequenced-before and sequenced-after in modern C++ versions. This means, the following will happen:
in any non-overlapping order: new A(), new B() - memory is allocated for A and B and constructors are run (these cannot be interleaved)
since B has a ctor, this ctor is run (sequenced-after allocation)
B's ctor throws
since B's ctor didn't complete, the memory allocated by new for constructing B will be freed, without calling dtor.
Note that the call to Foo's ctor would be sequenced-after the above, so it won't be reached.
Thus, B is not leaked. However, function parameters can be sequenced in any non-overlapping way, so A might or might not be leaked. This might, in theory, change from run to run.
If you do: Foo foo(MyPtr(new A()), MyPtr(new B()));, then you immediately encapsulate the pointers to smart pointers after new, so it won't leak.
Also, it's worth mentioning, while the memory for B is deallocated, any memory that's allocated in B's ctor and not deallocated till throw can still potentially leak. In this example there's no such allocation, but in actual codes it might occur. The only memory deallocated is that of the entire object being constructed.
Since C++17, no leak occurs in either case, but this interpretation hinges on the definition of initialization of a parameter. Does the initialization of a begin by evaluating new A(), or does it start after that expression has already been reduced to a pointer value? CWG2599 answers this question with the broader choice, as makes sense especially for aggregate initialization where the parameter obviously already exists (albeit only partially initialized) before all the initializer-clauses have been evaluated at all.
Consider the following class:
struct S { ~S() = delete; };
Shortly and for the purpose of the question: I cannot create instances of S like S s{}; for I could not destroy them.
As mentioned in the comments, I can still create an instance by doing S *s = new S;, but I cannot delete it as well.
Therefore, the only use I can see for a deleted destructor is something like this:
struct S {
~S() = delete;
static void f() { }
};
int main() {
S::f();
}
That is, define a class that exposes only a bunch of static functions and forbid any attempt to create an instance of that class.
What are the other uses (if any) of a deleted destructor?
If you have an object which should never, ever be deleted or stored on the stack (automatic storage), or stored as part of another object, =delete will prevent all of these.
struct Handle {
~Handle()=delete;
};
struct Data {
std::array<char,1024> buffer;
};
struct Bundle: Handle {
Data data;
};
using bundle_storage = std::aligned_storage_t<sizeof(Bundle), alignof(Bundle)>;
std::size_t bundle_count = 0;
std::array< bundle_storage, 1000 > global_bundles;
Handle* get_bundle() {
return new ((void*)global_bundles[bundle_count++]) Bundle();
}
void return_bundle( Handle* h ) {
Assert( h == (void*)global_bundles[bundle_count-1] );
--bundle_count;
}
char get_char( Handle const* h, std::size_t i ) {
return static_cast<Bundle*>(h).data[i];
}
void set_char( Handle const* h, std::size_t i, char c ) {
static_cast<Bundle*>(h).data[i] = c;
}
Here we have opaque Handles which may not be declared on the stack nor dynamically allocated. We have a system to get them from a known array.
I believe nothing above is undefined behavior; failing to destroy a Bundle is acceptable, as is creating a new one in its place.
And the interface doesn't have to expose how Bundle works. Just an opaque Handle.
Now this technique can be useful if other parts of the code need to know that all Handles are in that specific buffer, or their lifetime is tracked in specific ways. Possibly this could also be handled with private constructors and friend factory functions.
one scenario could be the prevention of wrong deallocation:
#include <stdlib.h>
struct S {
~S() = delete;
};
int main() {
S* obj= (S*) malloc(sizeof(S));
// correct
free(obj);
// error
delete obj;
return 0;
}
this is very rudimentary, but applies to any special allocation/deallocation-process (e.g. a factory)
a more 'c++'-style example
struct data {
//...
};
struct data_protected {
~data_protected() = delete;
data d;
};
struct data_factory {
~data_factory() {
for (data* d : data_container) {
// this is safe, because no one can call 'delete' on d
delete d;
}
}
data_protected* createData() {
data* d = new data();
data_container.push_back(d);
return (data_protected*)d;
}
std::vector<data*> data_container;
};
Why mark a destructor as delete?
To prevent the destructor from being invoked, of course ;)
What are the use cases?
I can see at least 3 different uses:
The class should never be instantiated; in this case I would also expect a deleted default constructor.
An instance of this class should be leaked; for example, a logging singleton instance
An instance of this class can only be created and disposed off by a specific mechanism; this could notably occur when using FFI
To illustrate the latter point, imagine a C interface:
struct Handle { /**/ };
Handle* xyz_create();
void xyz_dispose(Handle*);
In C++, you would want to wrap it in a unique_ptr to automate the release, but what if you accidentally write: unique_ptr<Handle>? It's a run-time disaster!
So instead, you can tweak the class definition:
struct Handle { /**/ ~Handle() = delete; };
and then the compiler will choke on unique_ptr<Handle> forcing you to correctly use unique_ptr<Handle, xyz_dispose> instead.
There are two plausible use cases. First (as some comments note) it could be acceptable to dynamically allocate objects, fail to delete them and allow the operating system to clean up at the end of the program.
Alternatively (and even more bizarre) you could allocate a buffer and create an object in it and then delete the buffer to recover the place but never prompt an attempt to call the destructor.
#include <iostream>
struct S {
const char* mx;
const char* getx(){return mx;}
S(const char* px) : mx(px) {}
~S() = delete;
};
int main() {
char *buffer=new char[sizeof(S)];
S *s=new(buffer) S("not deleting this...");//Constructs an object of type S in the buffer.
//Code that uses s...
std::cout<<s->getx()<<std::endl;
delete[] buffer;//release memory without requiring destructor call...
return 0;
}
None of these seems like a good idea except in specialist circumstances. If the automatically created destructor would do nothing (because the destructor of all members is trivial) then the compiler will create a no-effect destructor.
If the automatically created destructor would do something non-trivial you very likely compromise the validity of your program by failing to execute its semantics.
Letting a program leave main() and allowing the environment to 'clean-up' is a valid technique but best avoided unless constraints make it strictly necessary. At best it's a great way to mask genuine memory leaks!
I suspect the feature is present for completeness with the ability to delete other automatically generated members.
I would love to see a real practical use of this capability.
There is the notion of a static class (with no constructors) and so logically requiring no destructor. But such classes are more appropriately implemented as a namespace have no (good) place in modern C++ unless templated.
Creating an instance of an object with new and never deleting it is the safest way to implement a C++ Singleton, because it avoids any and all order-of-destruction issues. A typical example of this problem would be a "Logging" Singleton which is being accessed in the destructor of another Singleton class. Alexandrescu once devoted an entire section in his classical "Modern C++ Design" book on ways to cope with order-of-destruction issues in Singleton implementations.
A deleted destructor is nice to have so that even the Singleton class itself cannot accidentally delete the instance. It also prevents crazy usage like delete &SingletonClass::Instance() (if Instance() returns a reference, as it should; there is no reason for it to return a pointer).
At the end of the day, nothing of this is really noteworthy, though. And of course, you shouldn't use Singletons in the first place anyway.
(possibly related to How to implement a C++ method that creates a new object, and returns a reference to it which is about something different, but incidentially contains almost exactly the same code)
I would like to return a reference to a static local from a static function. I can get it to work, of course, but it's less pretty than I'd like.
Can this be improved?
The background
I have a couple of classes which don't do much except acquire or initialize a resource in a well-defined manner and reliably, and release it. They don't even need to know an awful lot about the resource themselves, but the user might still want to query some info in some way.
That's of course trivially done:
struct foo { foo() { /* acquire */ } ~foo(){ /* release */ } };
int main()
{
foo foo_object;
// do stuff
}
Trivial. Alternatively, this would work fine as well:
#include <scopeguard.h>
int main
{
auto g = make_guard([](){ /* blah */}, [](){ /* un-blah */ });
}
Except now, querying stuff is a bit harder, and it's less pretty than I like. If you prefer Stroustrup rather than Alexandrescu, you can include GSL instead and use some concoction involving final_act. Whatever.
Ideally, I would like to write something like:
int main()
{
auto blah = foo::init();
}
Where you get back a reference to an object which you can query if you wish to do that. Or ignore it, or whatever. My immediate thought was: Easy, that's just Meyer's Singleton in disguise. Thus:
struct foo
{
//...
static bar& init() { static bar b; return b; }
};
That's it! Dead simple, and perfect. The foo is created when you call init, you get back a bar that you can query for stats, and it's a reference so you are not the owner, and the foo automatically cleans up at the end.
Except...
The issue
Of course it couldn't be so easy, and anyone who has ever used range-based for with auto knows that you have to write auto& if you don't want surprise copies. But alas, auto alone looked so perfectly innocent that I didn't think of it. Also, I'm explicitly returning a reference, so what can auto possibly capture but a reference!
Result: A copy is made (from what? presumably from the returned reference?) which of course has a scoped lifetime. Default copy constructor is invoked (harmless, does nothing), eventually the copy goes out of scope, and contexts are released mid-operation, stuff stops working. At program end, the destructor is called again. Kaboooom. Huh, how did that happen.
The obvious (well, not so obvious in the first second!) solution is to write:
auto& blah = foo::init();
This works, and works fine. Problem solved, except... except it's not pretty and people might accidentially just do it wrong like I did. Can't we do without needing an extra ampersand?
It would probably also work to return a shared_ptr, but that would involve needless dynamic memory allocation and what's worse, it would be "wrong" in my perception. You don't share ownership, you are merely allowed to look at something that someone else owns. A raw pointer? Correct for semantics, but... ugh.
By deleting the copy constructor, I can prevent innocent users from running into the forgot-& trap (this will then cause a compiler error).
That is however still less pretty than I would like. There must be a way of communicating "This return value is to be taken as reference" to the compiler? Something like return std::as_reference(b);?
I had thought about some con trick involving "moving" the object without really moving it, but not only will the compiler almost certainly not let you move a static local at all, but if you manage to do it, you have either changed ownership, or with a "fake move" move-constructor again call the destructor twice. So that's no solution.
Is there a better, prettier way, or do I just have to live with writing auto&?
Something like return std::as_reference(b);?
You mean like std::ref? This returns a std::reference_wrapper<T> of the value you provide.
static std::reference_wrapper<bar> init() { static bar b; return std::ref(b); }
Of course, auto will deduce the returned type to reference_wrapper<T> rather than T&. And while reference_wrapper<T> has an implicit operatorT&, that doesn't mean the user can use it exactly like a reference. To access members, they have to use -> or .get().
That all being said however, I believe your thinking is wrong-headed. The reason is that auto and auto& are something that every C++ programmer needs to learn how to deal with. People aren't going to make their iterator types return reference_wrappers instead of T&. People don't generally use reference_wrapper in that way at all.
So even if you wrap all of your interfaces like this, the user still has to eventually know when to use auto&. So really, the user hasn't gained any safety, outside of your particular APIs.
Forcing the user to capture by reference is a three-step process.
First, make the returned thing non-copyable:
struct bar {
bar() = default;
bar(bar const&) = delete;
bar& operator=(bar const&) = delete;
};
then create a little passthrough function that delivers references reliably:
namespace notstd
{
template<class T>
decltype(auto) as_reference(T& t) { return t; }
}
Then write your static init() function, returning decltype(auto):
static decltype(auto) init()
{
static bar b;
return notstd::as_reference(b);
}
Full demo:
namespace notstd
{
template<class T>
decltype(auto) as_reference(T& t) { return t; }
}
struct bar {
bar() = default;
bar(bar const&) = delete;
bar& operator=(bar const&) = delete;
};
struct foo
{
//...
static decltype(auto) init()
{
static bar b;
return notstd::as_reference(b);
}
};
int main()
{
auto& b = foo::init();
// won't compile == safe
// auto b2 = foo::init();
}
Skypjack noted correctly that init() could be written just as correctly without notstd::as_reference():
static decltype(auto) init()
{
static bar b;
return (b);
}
The parentheses around the return (b) force the compiler to return a reference.
My problem with this approach is that c++ developers are often surprised to learn this, so it could be easily missed by a less experienced code maintainer.
My feeling is that return notstd::as_reference(b); explicitly expresses intent to code maintainers, much as std::move() does.
The best, most idiomatic, readable, unsurprising thing to do would be to =delete the copy constructor and copy assignment operator and just return a reference like everybody else.
But, seeing as you brought up smart pointers...
It would probably also work to return a shared_ptr, but that would involve needless dynamic memory allocation and what's worse, it would be "wrong" in my perception. You don't share ownership, you are merely allowed to look at something that someone else owns. A raw pointer? Correct for semantics, but... ugh.
A raw pointer would be perfectly acceptable here. If you don't like that, you have a number of options following the "pointers" train of thought.
You could use a shared_ptr without dynamic memory, with a custom deleter:
struct foo {
static shared_ptr<bar> init() { static bar b; return { &b, []()noexcept{} }; }
}
Although the caller doesn't "share" ownership, it's not clear what ownership even means when the deleter is a no-op.
You could use a weak_ptr holding a reference to the object managed by the shared_ptr:
struct foo {
static weak_ptr<bar> init() { static bar b; return { &b, []()noexcept{} }; }
}
But considering the shared_ptr destructor is a no-op, this isn't really any different from the previous example, and it just imposes on the user an unnecessary call to .lock().
You could use a unique_ptr without dynamic memory, with a custom deleter:
struct noop_deleter { void operator()() const noexcept {} };
template <typename T> using singleton_ptr = std::unique_ptr<T, noop_deleter>;
struct foo {
static singleton_ptr<bar> init() { static bar b; return { &b, {} }; }
}
This has the benefit of not needing to manage a meaningless reference count, but again the semantic meaning is not a perfect fit: the caller does not assume unique ownership, whatever ownership really means.
In library fundamentals TS v2 you can use observer_ptr, which is just a raw pointer that expresses the intent to be non-owning:
struct foo {
static auto init() { static bar b; return experimental::observer_ptr{&b}; }
}
If you don't like any of these options, you can of course define your own smart pointer type.
In a future standard you may be able to define a "smart reference" that works like reference_wrapper without the .get() by utilising overloaded operator..
If you want to use singleton, use it correctly
class Singleton
{
public:
static Singleton& getInstance() {
static Singleton instance;
return instance;
}
Singleton(const Singleton&) = delete;
Singleton& operator =(const Singleton&) = delete;
private:
Singleton() { /*acquire*/ }
~Singleton() { /*Release*/ }
};
So you cannot create copy
auto instance = Singleton::getInstance(); // Fail
whereras you may use instance.
auto& instance = Singleton::getInstance(); // ok.
But if you want scoped RAII instead of singleton, you may do
struct Foo {
Foo() { std::cout << "acquire\n"; }
~Foo(){ std::cout << "release\n"; }
Foo(const Foo&) = delete;
Foo& operator =(const Foo&) = delete;
static Foo init() { return {}; }
};
With the usage
auto&& foo = Foo::init(); // ok.
And copy is still forbidden
auto foo = Foo::init(); // Fail.
Someone would make a typo in one day and then we may or may not notice it in so many code, although we all know we should use auto& instead of auto.
The most convenient but very dangerous solution is using a derived class, as it breaks the strict-aliasing rule.
struct foo
{
private:
//Make these ref wrapper private so that user can't use it directly.
template<class T>
class Pref : public T {
private:
//Make ctor private so that we can issue a compiler error when
//someone typo an auto.
Pref(const Pref&) = default;
Pref(Pref&&) = default;
Pref& operator=(const Pref&) = default;
Pref& operator=(Pref&&) = default;
};
public:
static Pref<bar>& init() {
static bar b;
return static_cast<Pref<bar>&>(b);
}
///....use Pref<bar>& as well as bar&.
};
Say I have this class:
class Foo
{
public:
Foo()
{
bar = new Bar;
}
~Foo()
{
if(bar)
delete bar;
}
private:
Bar* bar;
};
Why would I want to use std::unique_ptr instead of raw pointers when unique_ptr is bloated? Are there any advantage? Is there any situation where my destructor won't be called?
The code you have above actually has a bug because you haven't defined a copy constructor or assignment operator. Imagine this code:
Foo one;
Foo two = one;
Because two is a copy of one, it's initialized using the default copy constructor - which makes both bar pointers point to the same object. This means that when the destructor for two fires, it will deallocate the same object shared by one, so one's destructor will trigger undefined behavior. Oops.
Now, if you didn't want to make your object copyable, you could say that explicitly like this:
class Foo
{
public:
Foo()
{
bar = new Bar;
}
Foo(const Foo&) = delete;
Foo& operator= (const Foo&) = delete;
~Foo()
{
if(bar)
delete bar;
}
private:
Bar* bar;
};
So that fixes that problem - but look at the amount of code involved! You had to explicitly delete two functions and write a destructor by hand.
Except there's another problem. Suppose I do this:
Foo one;
Foo two = std::move(one);
This initializes two by moving the contents of one into two. Or does it? Unfortunately, the answer is no, because the default move constructor will default to moving the pointer, which just does a straight pointer copy. So now you get the same thing as before. Oops.
Not to worry! We can fix this by defining a custom move constructor and move assignment operator:
class Foo
{
public:
Foo()
{
bar = new Bar;
}
Foo(const Foo&) = delete;
Foo& operator= (const Foo&) = delete;
Foo(Foo&& rhs)
{
bar = rhs.bar;
rhs.bar = nullptr;
}
Foo& operator= (Foo&& rhs)
{
if (bar != rhs.bar)
{
delete bar;
bar = rhs.bar;
rhs.bar = nullptr;
}
}
~Foo()
{
if(bar)
delete bar;
}
private:
Bar* bar;
};
Phew! That's a ton of code, but at least it's correct. (Or is it?)
On the other hand, imagine you wrote this:
class Foo
{
public:
Foo() : bar(new Bar) {
}
private:
std::unique_ptr<Bar> bar;
};
Wow, that's a lot shorter! And it automatically ensures that the class can't be copied, and it makes the default move constructor and move assignment operators work correctly.
So one huge advantage of std::unique_ptr is that it automatically handles resource management, yes, but another one is that it plays nicely with copy and move semantics and doesn't work in unexpected ways. That's one of the main reasons to use it. You can say what you mean - "I'm the only one who should know about this thing, and you can't share it" - and the compiler will enforce it for you. Enlisting the compiler to help you avoid mistakes is almost always a good idea.
As for bloat - I'd need to see evidence of that. std::unique_ptr is a thin wrapper on a pointer type and a good optimizing compiler should have no trouble generating good code for it. True, there's the constructor, destructor, etc. associated with std::unique_ptr, but a reasonable compiler will inline those calls, which essentially just do the same thing as what you had initially described.
You are basically relying on a class to manage a pointer's lifetime, but neglect to consider that pointers get passed between functions, returned from functions, and generally exist everywhere. What if the pointer in your example needs to outlive the class? What if it needs to be deleted before the class is destroyed?
Consider this function:
Bar * doStuff(int param) {
return new Bar(param);
}
You now have a dynamically allocated object that may leak if you forget to delete it. Perhaps you didn't read the documentation, or perhaps the documentation is lacking. Regardless, this function puts an unnecessary burden on you to destroy the the returned instance of Bar.
Now consider:
std::unique_ptr<Bar> doStuffBetter(int param) {
return new Bar(param);
}
The returned unique_ptr manages the lifetime of the pointer it wraps. The fact that the function returns a unique_ptr eliminates any confusion about ownership and lifetime. Once the returned unique_ptr goes out of scope and its destructor called, the instance of Bar is automatically deleted.
unique_ptr is just one of several methodologies that the standard library provides to make using pointers a less messy process and express ownership. It is both lightweight and works largely like a normal pointer, save for copying.
It is easier to be exception-safe by using std::unique_ptr (RAII) instead of raw pointers.
Consider a class has two member variables acquiring memory in its constructor.
class Foo
{
public:
Foo()
{
bar = new Bar;
car = new Car; // <- What happens when this throws exception?
}
~Foo()
{
if(bar)
delete bar;
if(car)
delete car;
}
private:
Bar* bar;
Car* car;
};
If the constructor of Foo throws exception, Foo is not successfully constructed, therefore its destructor is not called.
When new Car throws exception, bar is not deleted, so there will be a memory leak.
Now consider the code using std::unique_ptr.
class Foo
{
public:
Foo() : bar(std::make_unique<Bar>()), car(std::make_unique<Car>()) {}
private:
std::unique_ptr<Bar> bar;
std::unique_ptr<Car> car;
};
If the constructor of Foo throws exception, Foo is not successfully constructed, therefore its destructor is not called.
However, destructors of successfully created member instances are called.
Even std::make_unique<Car>() throws exception, destructor of bar is called, so there will be no memory leak.