C++ constructor thread safety - c++

Let's say I have a member variable vector initialised in the constructor, and this vector is read (not written to anywhere else) in several other member functions. Would I need to protect access to the vector (including in the constructor), or is it guaranteed that the object will be fully initialised and flushed to main memory before it's used in other threads?
Let me provide an example:
class A
{
public:
A();
void f1();
void f2();
private:
std::vector<int> v;
};
A::A()
{
// do some setup work in v
v.push_back(1);
}
// called from thread1
void A::f1()
{
// some readonly work on v
for (auto i : v) {
// do something on i
}
}
// called from thread2
void A::f2()
{
// more readonly work on v
if (v.empty()) {
// do other work
}
}
Do I need to lock-protect v in A::A(), A::f1() and A::f2()?

An object is created by a single thread, so you never have to worry about thread safety when running code inside the constructor that touches member variables. However, if you are using static variables within the constructor then you may need to add some form of locking around the access.
There is an edge case where code within a constructor can be called by multiple threads, and this is when you are using either placement new. For example, let's say you've got a buffer somewhere, and you're going to allocate an object into it:
byte buffer[100];
Foo *foo = new (buffer) Foo;
Here, unless you are locking around the call to new then it's possible for two or more constructors to run in parallel as they're running against the same block of memory. However, this is a real specialized edge-case and would require special handling (eg locking around the placement-new construction).

An object is constructed by a single thread.
Other threads can access the object only by means of the instance reference.
In other words, the object's constructor will have finished its work before other threads call a method.
You therefore don't need to implement thread-safe code within a constructor.
Of course, in case another object is passed to the constructor as a parameter, eventual access to that object within the constructor, should be thread-safe.

As stated in the other answers, there is no point in implementing synchronization primitives in the constructer, but that doesn't mean you can't have a race, if you don't synchronize externally:
std::atomic<A*> g_ptr = nullptr;
void threadFun1() {
g_ptr.store(new A{}, std::memory_order_relaxed);
}
void threadFun2() {
A* l_ptr = nullptr;
while (l_ptr == nullptr) {
l_ptr = g_ptr.load(std::memory_order_relaxed);
}
l_ptr->f1();
}
In above code, you have a data race between the constructor of A and f1. The problem is that - without synchonization - from the point of view of thread2, g_ptr might be written before the object is completely constructed.
However, there is nothing you can do inside the constructor to prevent this kind of race. Instead you have to use external means of synchronization, like using non-relaxed memory ordering for the atomic load and store operations or starting thread2 from within thread1 after the global variable is set.

Take this code example below:
model.h
namespace Stackoverflow {
class Model {
public:
Model();
~Model();
std::vector<int> *integers() const { return _integers.get(); }; // read only
private:
std::unique_ptr<std::vector<int>> _integers; // registered before constructor
};
}
model.cpp
Stackoverflow::Model::Model() {
_integers = std::make_unique<std::vector<int>>(); // initialized
}
Stackoverflow::Model::~Model() {
_integers.release();
}
The private member "_integers" will be registered but not initialized until the constructor is being called by the caller.
Stackoverflow::Model stackoverflow;
When another thread want to access this vector, call the getter.
auto *vector = stackoverflow.integers();
The member will be fully initialized when the caller is actually asking for the vector.

Related

C++ std::shared_ptr custom deleter thread safety

[edited with a more concrete example]
Suppose I have a thread-safe object (all public member use a mutex) and a shared_ptr with a custom deleter, like so:
class A {
public:
void update(int x);
void print_sum();
...
}
class AContainer {
private SomeConcurrentMap<string, shared_ptr<A>> aMap;
void newA(string name) {
aMap.emplace(name, shared_ptr<A>(new A, [](A *p){p->print_sum(); delete p;}));
}
void finalizeA(string name) {
aMap.erase(name);
}
shared_ptr<A> getA(string name) const {
// fixme handle case of not found...
return aMap.find(name).second;
}
};
void someFunctionInSomeThread(const AContainer &cont, string name, int c) {
// fixme handle case of not found...
cont.getA(name)->update(c);
}
Let's assume all A operation are protected by a mutex, and that SomeConcurrentMap is thread-safe. The usage is scenario is:
call AContainer::newA() from any thread
call someFunctionInSomeThread() multiple times by multiple threads
call AContainer::finalizeA() from any thread - possibly in parallel to step 2
And the idea that A::print_sum() is called after both step 3 completed and all running A::update() operations complete.
Is it safe to assume that by the time p->print_sum() is called, all the A::update() operations on the object have been called?
Is it safe to assume that by the time p->print_sum() is called, all the A::update() operations on the object have been called?
Yes, it is safe to assume that. Only one thread is going to call the destructor, and no thread is going to call the destructor before calling other member functions of A (such a thread would be invoking UB even if no other threads existed, e.g. by keeping a raw pointer after destroying the shared pointer and then accessing the object via the raw pointer).

Is it safe to use a boost::signals2::scoped_connection object as member of a class for automatic connection lifetime?

I wondered whether the following code is safe with respect to the fact that the signal might be triggered by a different thread:
using IntSignal = boost::signals2::signal<void(int)>;
class Foo
{
public:
Foo(IntSignal& signal)
: some_resource(new int(0))
{
scoped_connection = signal.connect([this](int i) { some_action(i); });
}
~Foo()
{
delete some_resource;
}
private:
void some_action(int i)
{
*some_resource = i;
}
int* some_resource;
boost::signals2::scoped_connection scoped_connection;
}
EDIT: added an imaginary resource, destructor and an implementation for some_action to make it more clear. With this question I would like to clarify whether my assumption is correct that the signal's slot might be called after Foo's destructor but before scoped_connection's destructor. I omitted a mutex protecting some_resource for brevity, however, it is not relevant for the question.
Although the connection will be dropped when a Foo instance is destroyed, there might be a tiny gap betwen Foo's own destructor invocation and the destruction of Foo's members. This might be even more problematic if resources are being used within some_action after they have been destructed.
Should I rather use normal connections and disconnect them in Foo's destructor? And would it be safe to have the scoped_connection member as last member of the class (that should get destroyed first) and omit any destruction logic?
You are right, there is a possible race if Foo's destructor is invoked while the signal is running and accessing some_resource.
A safe solution would be to extend the life of Foo while the slots are running:
class Foo : public std::enable_shared_from_this<Foo>
{
public:
Foo(IntSignal& signal)
: some_resource(new int(0))
{
// moved connection initialization to a method since weak_from_this will
// be empty inside the constructor. It is initialized only afterwards.
// It also make sense to connect your signal only after object
// is fully initialized
}
void InitConnection()
{
auto weak_self = weak_from_this();
scoped_connection = signal.connect(
[weak_self](int i)
{
if (auto self = weak_self.lock())
{
// we managed to promote weak_self to a shared_ptr, 'this' will be alive
// as long as this scope lives
some_action(i); // safe
}
});
}
~Foo()
{
// will only be invoked after Foo's reference count drops to zero.
// not during the signal is emitted
delete some_resource;
}
private:
void some_action(int i)
{
*some_resource = i;
}
int* some_resource;
boost::signals2::scoped_connection scoped_connection;
}
Notes:
enable_shared_from_this initializes a weak_ptr to 'this'. It is a great tool for the situation you described. See more here.
Make sure you create Foo as a shared_ptr, otherwise weak_from_this will not work.
Remember: Foo is shared between 2 threads.

No thread-safety between different vectors in C++?

My problem deals with the usage of different vectors at the same time. I know I can't expect the same vector to work in multiple threads simultaneously. I've broken down the program so it is easier to understand it. I have a ThreadClass class that has a constructor which just adds an element to the vector k and then calls a thread toCall which then outputs the size of the vector which is supposed to be one. The object of this class is created inside of a different vector inside of the main() function using vector's push_back member.
The output turns out to be 0. Sometimes I can get 1 as well. I can produce more of the number 1 if I switch to debug mode. I have tested this problem on a gnu C++17 compiler (Ubuntu 16.04) and a Visual Studio compiler (Windows 10). My question is now if this example shows that I should avoid using vectors in multi-threaded programs totally?
class ThreadClass
{
private:
std::vector<int> k;
std::thread thr;
public:
ThreadClass() {
k.push_back(27);
thr = std::thread(&ThreadClass::toCall, this);
}
void toCall() {
std::cout << k.size() << std::endl;
}
void close() {
if (thr.joinable())thr.join();
}
};
int main(){
std::vector<ThreadClass> lols;
lols.push_back(ThreadClass());
lols[0].close();
return 0;
}
The problem is that a value of type ThreadClass holds a reference to itself. Specifically, thr contains a copy of this.
When you copy or move such a value, e.g. when the temporary ThreadClass() is moved into lols, the duplicate holds a duplicate this ptr, i.e. it points to the old temporary, whose lifetime ends after the call to lols.push_back finishes.
We can replicate this problem without threads:
class Foo
{
private:
std::vector<int> k;
Foo* possibly_this;
public:
Foo() {
k.push_back(27);
possibly_this = this;
}
void toCall() {
std::cout << possibly_this->k.size() << std::endl;
}
};
int main(){
std::vector<Foo> lols;
lols.push_back(Foo{});
lols[0].toCall();
}
(For me, it prints 0 with -O0 on 7.3.1, but again, it's UB, so it could do anything on your machine.)
lols.emplace() will not help. If a std::vector resizes, then all pointers/iterators into it are invalidated. Unfortunately, you can't change the pointers stored in thr, so you're left with one solution: disable ThreadClass's copy and move constructors, like so:
//within the definition of ThreadClass
ThreadClass(ThreadClass const&) = delete;
In order to place ThreadClass in a container, you will need an additional level of indirection to allow the actual object of a value of type ThreadClass to have a stable location. Either std::list<ThreadClass> or std::vector<std::unique_ptr<ThreadClass>> will do the trick.
One issue is that your thread can call toCall before the constructor returns. It's not a good idea to go creating threads that call back into the object in the constructor. Defer the thread creation to some kind of start or launch function and call that after the constructor returns.
This is also a problem:
lols.push_back(ThreadClass());
Here, the destructor (of the temporary) can even run before toCall gets called! That's definitely not going to work. That's another really good reason not to create a thread in a constructor -- it makes temporary objects disastrous.

Can I access a static local while it is being constructed in C++?

Static locals are guaranteed to be instantiated at first use by the C++ standard. However, I'm wondering what happens if I access a static local object while it is beeing constructed. I assume that this is UB.
But what are the best practices to avoid this in the following situation?
A problem situation
The Meyers Singleton pattern uses a static local in a static getInstance() method to construct the object on the first use. Now if the constructor (directly or indireclty) calls getInstance() again, we face
a situation where the static initialization is not yet completed. Here is a minimal example, that illustrates the problem situation:
class StaticLocal {
private:
StaticLocal() {
// Indirectly calls getInstance()
parseConfig();
}
StaticLocal(const StaticLocal&) = delete;
StaticLocal &operator=(const StaticLocal &) = delete;
void parseConfig() {
int d = StaticLocal::getInstance()->getData();
}
int getData() {
return 1;
}
public:
static StaticLocal *getInstance() {
static StaticLocal inst_;
return &inst_;
}
void doIt() {};
};
int main()
{
StaticLocal::getInstance()->doIt();
return 0;
}
In VS2010, this works without problems, but VS2015 deadlocks.
For this simple, reduced situation, the obvious solution is to direclty call getData(), without calling getInstance() again. However, in more complex scenarios (as my actual situation), this solution is not feasible.
Attempting a solution
If we change the getInstance() method to work on a static local pointer like this (and thus abandon the Meyers Singleton pattern):
static StaticLocal *getInstance() {
static StaticLocal *inst_ = nullptr;
if (!inst_) inst_ = new StaticLocal;
return inst_;
}
It is clear that we get an endless recursion. inst_ is nullptr on the first invokation, so we call the constructor with new StaticLocal. At this point, inst_ is still nullptr as it will only get assigned when
the constructor finishes. However, the constructor will call getInstance() again, finding a nullptr in inst_, and thus call the constructor again. And again, and again, ...
A possible solution is to move the constructor's body into the getInstance():
StaticLocal() { /* do nothing */ }
static StaticLocal *getInstance() {
static StaticLocal *inst_ = nullptr;
if (!inst_) {
inst_ = new StaticLocal;
inst_->parseConfig();
}
return inst_;
}
This will work. However, I'm not happy with this situation, as a constructor should, well, construct a complete object. It is debateable if this situation can be made an exception, as it is a singleton. However, I dislike it.
But what's more, what if the class has a non-trivial destructor?
~StaticLocal() { /* Important Cleanup */ }
In the above situation, the destructor is never called. We loose RAII and thus one important distinguishing feature of C++! We are in a world like Java or C#...
So we could wrap our singleton in some sort of smart pointer:
static StaticLocal *getInstance() {
static std::unique_ptr<StaticLocal> inst_;
if (!inst_) {
inst_.reset(new StaticLocal);
inst_->parseConfig();
}
return inst_.get();
}
This will correctly call the destructor on program exit. But it forces us to make the destructor public.
At this point, I feel I'm doing the compiler's job...
Back to the original question
Is this situation really undefined behaviour? Or is it a compiler bug in VS2015?
What is the best solution to such a situation, prefably without dropping a full constructor, and RAII?
This leads to undefined behaviour by c++ 11 standard. The relevant section is 6.7:
If control enters the declaration concurrently while the variable is
being initialized, the concurrent execution shall wait for completion
of the initialization. If control re-enters the declaration
recursively while the variable is being initialized, the behavior is
undefined.
The example from the standard is bellow:
int foo(int i) {
static int s = foo(2*i); // recursive call - undefined
return i+1;
}
You are facing the deadlock since MSVC inserts mutex lock/unlock to make static variable initialization thread safe. Once you call it recursively, you are locking the same mutex two times in the same thread, what leads to dead lock.
This is how static initialization is implemented internally in llvm compiler.
The best solution IMO is to do not use singletons at all. Significant group of developers tend to think that singleton is anti-pattern. The issues like you mentioned is really hard to debug, because it occurs before main. Because order of globals initialization is undefined. Also, multiple translation units might be involved, so compiler won't catch this types of errors. So, when I faced the same problem in production code, I was obliged to remove all of the singletons.
If you still think that singleton is the right way to go, then you need to re-structurize your code somehow when your singleton object owns (holds them as members, for example) all the classes that calls GetInstance during the singleton initialization. Think of your classes like ownership tree, where the singleton is the root. Pass reference to parent, when you create a child, if child needs it.
The problem is that inside the class, you should be using "this" instead of calling getInstance, in particular:
void parseConfig() {
int d = StaticLocal::getInstance()->getData();
}
Should simply be:
void parseConfig() {
int d = getData();
}
The object is a singleton because the constructor is private and thus the user cannot construct an arbitrary number of objects. It's bad design to write the whole class assuming there will be only one instance of the object ever. At some point somebody may stretch the concept of a singleton like this:
static StaticLocal *getInstance(int idx) {
static StaticLocal inst_[3];
if (idx < 0 || idx >= 3)
throw // some error;
return &inst_[idx];
}
When that happens, it's much easier to update the code if there aren't calls to getInstance() throughout the class.
Why do changes like this happen? Imagine you were writing a class 20 years ago to represent the CPU. Of course there will only ever be one CPU in the system, so you make it a singleton. Then, suddenly, multi-core systems become commonplace. You still want only as many instances of the CPU class as there are cores in the system, but you won't know until the program is run how many cores are actually on a given system.
Moral of the story: Using the this pointer not only avoids recursively calling getInstance(), but future proofs your code as well.
Actually this code in its current form is stuck into 3-way infinite recursion. Hence it will never work.
getInstance() --> StaticLocal()
^ |
| |
----parseConfig() <---
To let it work, anyone of the above 3 methods has to compromise and come out of the vicious circle. You judged it right, parseConfig() is the best candidate.
Let's assume that all the recursive content of constructor is put into parseConfig() and non-recursive contents are retained in constructor. Then you may do following (only relevant code):
static StaticLocal *s_inst_ /* = nullptr */; // <--- introduce a pointer
public:
static StaticLocal *getInstance() {
if(s_inst_ == nullptr)
{
static StaticLocal inst_; // <--- RAII
s_inst_ = &inst_; // <--- never `delete s_inst_`!
s_inst_->parseConfig(); // <--- moved from constructor to here
}
return s_inst_;
}
This works fine.
One straight forward way of solving this is to separate the responsibilities, in this case "whatever StaticLocal is supposed to do" and "reading the configuration data"
class StaticLocal;
class StaticLocalData
{
private:
friend StaticLocal;
StaticLocalData()
{
}
StaticLocalData(const StaticLocalData&) = delete;
StaticLocalData& operator=(const StaticLocalData&) = delete;
int getData()
{
return 1;
}
public:
static StaticLocalData* getInstance()
{
static StaticLocalData inst_;
return &inst_;
}
};
class StaticLocal
{
private:
StaticLocal()
{
// Indirectly calls getInstance()
parseConfig();
}
StaticLocal(const StaticLocal&) = delete;
StaticLocal& operator=(const StaticLocal&) = delete;
void parseConfig()
{
int d = StaticLocalData::getInstance()->getData();
}
public:
static StaticLocal* getInstance()
{
static StaticLocal inst_;
return &inst_;
}
void doIt(){};
};
int main()
{
StaticLocal::getInstance()->doIt();
return 0;
}
This way, StaticLocal does not call itself, the circle is broken.
Also, you have cleaner classes. If you move the implementation of StaticLocal into a separate compile unit, users of static local won't even know that the StaticLocalData thingy exists.
There is a good chance that you will find that you do not need the functionality of StaticLocalData to be wrapped into a Singleton.
All versions of the C++ standard have a paragraph that makes this undefined behaviour. In C++98, Section 6.7 para 4.
An implementation is permitted to perform early initialization of
other local objects with static storage duration under the same
conditions that an implementation is permitted to statically
initialize an object with static storage duration in namespace scope
(3.6.2). Otherwise such an object is initialized the first time
control passes through its declaration; such an object is considered
initialized upon the completion of its initialization. If the
initialization exits by throwing an exception, the initialization is
not complete, so it will be tried again the next time control enters
the declaration. If control reenters the declaration (recursively)
while the object is being initialized, the behavior is undefined.
All subsequent standards have essentially the same paragraph (only differences are inconsequential - such as section numbering for cross-referencing, etc).
What you have done is implement the constructor of your singleton so it calls the function which constructs it. getInstance() creates the object, the constructor (indirectly) calls getInstance(). Hence it runs afoul of the last sentence in the quote above, and introduces undefined behaviour.
The solution, as with anything recursive, is to either reimplement so recursion does not occur, or to prevent interference between the first call and any recursive calls.
There are three ways to achieve this.
The first, which you have said you don't want, is to construct an object and then parse data to initialise it (two-stage construction).
The second is to parse the data first, and only construct the object if the parsed data is valid (i.e. suitable for use in constructing the object).
The third is for the constructor to handle the parsing (which you are trying to do) but, if parsed data is invalid, to force the constructor to fail (which your code does not do).
An example of the third is to leave the getInstance() alone, and restructure the constructor so it never calls getInstance().
static StaticLocalData* getInstance()
{
static StaticLocalData inst_;
return &inst_;
}
StaticLocalData::StaticLocalData()
{
parseConfig();
}
void StaticLocalData::parseConfig()
{
int data = getData(); // data can be any type you like
if (IsValid(data))
{
// this function is called from constructor so simply initialise
// members of the current object using data
}
else
{
// okay, we're in the process of constructing our object, but
// the data is invalid. The constructor needs to fail
throw std::invalid_argument("Construction of static local data failed");
}
}
In the above, IsValid() represents a function or expression that checks if the parsed data is valid.
This approach actually exploits the second last sentences in the paragraph I quoted above from the standard. It has the effect of ensuring that calling staticLocal::getInstance() repeatedly will keep resulting in an exception until the parsing succeeds. Once the parsing has succeeded, the object will exist, and no further attempt will be made to it (it's address will simply be returned instead).
If the caller does not catch the exception, the effect is simple - the program will terminate(). If the caller does catch the exception, it should not try to use the pointer.
try
{
StaticLocal *thing = StaticLocal::getInstance();
// code using thing here will never be reached if an exception is thrown
}
catch (std::invalid_argument &e)
{
// thing does not exist here, so can't be used
// Worry about recovery, not trying to use thing
}
So, yes, your approach introduces undefined behaviour. But same part of the standard that makes the behaviour undefined also provides the basis for a solution.
In terms of dtor, I think you don't have to worry about it. Once you define it, then it will be automatically called after main() exits.
see How to implement multithread safe singleton in C++11 without using <mutex>
singleton declaration in c++11 is thread safe by standard. In VS2015 it may be implemented by mutex.
So, you last solution is fully applicable
StaticLocal() { /* do nothing */ }
static StaticLocal *getInstance() {
static StaticLocal inst_;
std::call_once(once_flag, [&inst_]() {inst_.parseConfig(); return &inst_;});
return &inst_;
}
about destructor: you can register you singleton destructor by using
int atexit(void (*function)(void));. This applied in Linux and may be exist in Win too, as function from standard library.

Is there a potential for resource leak/double free here?

The following sample (not compiled so I won't vouch for syntax) pulls two resources from resource pools (not allocated with new), then "binds" them together with MyClass for the duration of a certain transaction.
The transaction, implemented here by myFunc, attempts to protect against leakage of these resources by tracking their "ownership". The local resource pointers are cleared when its obvious that instantiation of MyClass was successful. The local catch, as well as the destructor ~MyClass return the resources to their pool (double-frees are protected by teh above mentioned clearing of the local pointers).
Instantiation of MyClass can fail and result in an exception at two steps (1) actual memory allocation, or (2) at the constructor body itself. I do not have a problem with #1, but in the case of #2, if the exception is thrown AFTER m_resA & m_resB were set. Causing both the ~MyClass and the cleanup code of myFunc to assume responsibility for returning these resources to their pools.
Is this a reasonable concern?
Options I have considered, but didn't like:
Smart pointers (like boost's shared_ptr). I didn't see how to apply to a resource pool (aside for wrapping in yet another instance).
Allowing double-free to occur at this level but protecting at the resource pools.
Trying to use the exception type - trying to deduce that if bad_alloc was caught that MyClass did not take ownership. This will require a try-catch in the constructor to make sure that any allocation failures in ABC() ...more code here... wont be confused with failures to allocate MyClass.
Is there a clean, simple solution that I have overlooked?
class SomeExtResourceA;
class SomeExtResourceB;
class MyClass {
private:
// These resources come out of a resource pool not allocated with "new" for each use by MyClass
SomeResourceA* m_resA;
SomeResourceB* m_resB;
public:
MyClass(SomeResourceA* resA, SomeResourceB* resB):
m_resA(resA), m_resB(resB)
{
ABC(); // ... more code here, could throw exceptions
}
~MyClass(){
if(m_resA){
m_resA->Release();
}
if(m_resB){
m_resB->Release();
}
}
};
void myFunc(void)
{
SomeResourceA* resA = NULL;
SomeResourceB* resB = NULL;
MyClass* pMyInst = NULL;
try {
resA = g_pPoolA->Allocate();
resB = g_pPoolB->Allocate();
pMyInst = new MyClass(resA,resB);
resA=NULL; // ''ownership succesfully transfered to pMyInst
resB=NULL; // ''ownership succesfully transfered to pMyInst
// Do some work with pMyInst;
...;
delete pMyInst;
} catch (...) {
// cleanup
// need to check if resA, or resB were allocated prior
// to construction of pMyInst.
if(resA) resA->Release();
if(resB) resB->Release();
delete pMyInst;
throw; // rethrow caught exception
}
}
Here is your chance for a double call to release:
void func()
{
MyClass a(resourceA, resourceB);
MyClass b(a);
}
Whoops.
If you use an RIAA wrapper fro your resources you will be much less likely to make mistakes. Doing it this way is error prone. You are currently missing the copy constructor and assignment operator on MyClass that could potentially lead to a double call to Release() as shown above.
Because of the complexity of handling resource a class should only own one resource. If you have multiple resource delegate their ownership to a class that it dedicated to their ownership and use multiple of these objects in your class.
Edit 1
Lut us make some assumptions:
Resources are shared and counted. You increment the count with Acquire() and decrement the count with Release(). When count reaches zero they are automatically destroyed.
class ReferenceRapper
{
ReferenceBase* ref;
public:
ReferenceWrapper(ReferenceBase* r) : ref (r) {/* Pool set the initial count to 1 */ }
~ReferenceWrapper() { if (ref) { ref->Release();} }
/*
* Copy constructor provides strong exception guarantee (aka transactional guarantee)
* Either the copy works or both objects remain unchanged.
*
* As the assignment operator is implemented using copy/swap it also provides
* the strong exception guarantee.
*/
ReferenceWrapper(ReferenceWrapper& copy)
{
if (copy.ref) {copy.ref->Acquire();}
try
{
if (ref) {ref->Release();}
}
catch(...)
{
if (copy.ref)
{ copy.ref->Release(); // old->Release() threw an exception.
// Must reset copy back to its original state.
}
throw;
}
ref = copy.ref;
}
/*
* Note using the copy and swap idium.
* Note: To enable NRVO optimization we pass by value to make a copy of the RHS.
* rather than doing a manual copy inside the method.
*/
ReferenceWrapper& operator(ReferenceWrapper rhsCopy)
{
this->swap(rhsCopy);
}
void swap(ReferenceWrapper& rhs) throws ()
{
std::swap(ref, rhs.ref);
}
// Add appropriate access methods like operator->()
};
Now that the hard work has been done (managing resources). The real code becomes trivial to write.
class MyClass
{
ReferenceWrapper<SomeResourceA> m_resA;
ReferenceWrapper<SomeResourceB> m_resB;
public:
MyClass(ReferenceWrapper<SomeResourceA>& a, ReferenceWrapper<SomeResourceB>& b)
: m_resA(a)
, m_resB(b)
{
ABC();
}
};
void myFunc(void)
{
ReferenceWrapper<SomeResourceA> resA(g_pPoolA->Allocate());
ReferenceWrapper<SomeResourceB> resB(g_pPoolB->Allocate());
std::auto_ptr<MyClass> pMyInst = new MyClass(resA, resB);
// Do some work with pMyInst;
}
Edit 2 Based on comment below that resources only have one owner:
If we assume a resource has only one owner and is not shared then it becomes trivial:
Drop the Release() method and do all the work in the destructor.
Change the Pool methods so that the construct the pointer into a std::auto_ptr and return the std::auto_ptr.
Code:
class MyClass
{
std::auto_ptr<SomeResourceA> m_resA;
std::auto_ptr<SomeResourceB> m_resB;
public:
MyClass(std::auto_ptr<SomeResourceA>& a, std::auto_ptr<SomeResourceB>& b)
: m_resA(a)
, m_resB(b)
{
ABC();
}
};
void myFunc(void)
{
std::auto_ptr<SomeResourceA> resA(g_pPoolA->Allocate());
std::auto_ptr<SomeResourceB> resB(g_pPoolB->Allocate());
std::auto_ptr<MyClass> pMyInst = new MyClass(resA, resB);
// Do some work with pMyInst;
}
I don't see any leak in this small code.
If the constructor throws exception, then the destructor would not be called, since the object never existed. Hence I don't see double-delete either!
From this article by Herb Sutter :Constructor Exceptions in C++, C#, and Java:
constructor conceptually turns a
suitably sized chunk of raw memory
into an object that obeys its
invariants. An object’s lifetime
doesn’t begin until its constructor
completes successfully. If a
constructor ends by throwing an
exception, that means it never
finished creating the object and
setting up its invariants — and at
the point the exceptional constructor
exits, the object not only doesn’t
exist, but never existed.
A destructor/disposer conceptually
turns an object back into raw memory.
Therefore, just like all other
nonprivate methods,
destructors/disposers assume as a
precondition that “this” object is
actually a valid object and that its
invariants hold. Hence,
destructors/disposers only run on
successfully constructed objects.
I think this should clear your doubts!
Your code is fine. But to make it even better, use some kind of smart-pointer!
Edit: for example you can use shared_ptr:
class SomeExtResourceA;
class SomeExtResourceB;
class MyClass {
private:
// These resources come out of a resource pool not allocated with "new" for each use by MyClass
shared_ptr<SomeResourceA> m_resA;
shared_ptr<SomeResourceB> m_resB;
public:
MyClass(const shared_ptr<SomeResourceA> &resA, const shared_ptr<SomeResourceB> &resB):
m_resA(resA), m_resB(resB)
{
ABC(); // ... more code here, could throw exceptions
}
}
};
void myFunc(void)
{
shared_ptr<SomeResourceA> resA(g_pPoolA->Allocate(), bind(&SomeResourceA::Release, _1));
shared_ptr<SomeResourceB> resB(g_pPoolB->Allocate(), bind(&SomeResourceB::Release, _1));
MyClass pMyInst(resA,resB);
// you can reset them here if you want, but it's not necessery:
resA.reset(), resB.reset();
// use pMyInst
}
I find this solution with RAII much simpler.
Just put if (pMyInst) { ... } around release/delete code in your catch and you are fine.
The classic usage to explicitly take ownership is the std::auto_ptr
Something like this:
std::auto_ptr<SomeResourceA>(g_pPoolA->Allocate()) resA;
std::auto_ptr<SomeResourceB>(g_pPoolB->Allocate()) resB;
pMyInst = new MyClass(resA.release(),resB.release());
You transfer the ownership when you call the constructor.