Minimalistic destructors? - c++

We have some issue with my friend. Assume, we have a class which implements database connection, like this:
class DB
{
void Connect();
void Disconnect();
// ...
~DB();
};
In my opinion, destructor should be minimalistic, which means destructor should not call Disconnect method when connection was established. I think, that this should be done by separate method (disconnect() in this example). Am I correct, or my friend is?
PS. Community Wiki?

Your destructor should be enough to clean up all the resources that were acquired during the object lifetime. This might or might not include ending connnections. Otherwise who will do the cleanup if an exception is thrown?

The RAII idioms says: acquire in the constructor and release in the deconstructor. You must guarantee that your deconstructor will NOT throw anything. Otherwise you will have core dump (or undefined behaviour) if your object deconstructor will throw an exception during the stack-unwind.
Also in your specific case I will probably implement a reference counting mechanism, and call the disconnect just when you haven't any more object using the connection.

According to the syntax it looks like C++. Am I correct? Because if so, you can (and it is highly recommended to) use the RAII idiom. That means that you aquire the DB connection on construction, free it (disconnect) on destruction.
Good reference: What's RAII All About?

From the class user point of view, I believe it is better to try and disconnect the database connection when it should instead of assuming the destructor will do the job.
However, bad things happen, most notably exceptions, and you must guarantee that cleanup will occur regardless of what happened. This is why your destructor should nevertheless disconnect if necessary (i.e: if it hasn't been explicitly called by the user).

Related

Perform task in destructor

Is it a good technique to perform important/critical tasks of an object in the destructor?
Such as:
class MyObject{
~MyObject() {
Execute();
}
void Execute() {...}
};
Destructors are meant to be a way to automatically clean up resources held by an object when it goes out-of- scope. Nothing else should be done in destructor. But the clean up may involve critical or complex processing. Also make sure exception does not leave your destructor. That will lead to terminate your program unexpectedly if the destrcutor was originally called because of stack unwinding due to another exception.
It is good practice to provide public interface for critical clean-up/resource management, so that client code can call it and handle if any exception arises. You can check if the clean up process is done in the destructor, if not perform it, but swallow any exception thrown.
To summarize, it is NOT a good practice to perform anything at all (whether critical or not) other than resource clean up in destructor.
Generally the answer is NO. E.g. if the program crashes, destructor won't be called. There're other circumstances when dtor isn't called. Destructor is dedicated method for clean up. Class users expect such behavior.

Is it bad practice to call an observer in a destructor?

I have an object that sends a signal when a group of tasks completes. These tasks are executed independently in a thread pool. I want to send a notification to an observer when all of the tasks in a group are complete.
Essentially this boils down to a reference counting scheme. When ref=0, I send the notification. One implementation of this would be to leverage boost smart pointers (or any ref counted auto).
class TaskCompletionNotifier {
~TaskCompletionNotifier() {
_listener->notify();
}
setListener(listener);
Listener _listener;
}
class Task {
boost::shared_ptr<TaskCompletionNotifier> _notifier;
}
My question is, is it bad practice to perform this call-out in the destructor of an object?
Is this inherently bad? No.
Does it open up potential pitfalls? Yes.
Make sure you don't allow any exceptions to escape the destructor, and you're best off making sure that _listener->notify() doesn't end up modifying any member data of this object: it's safe and okay if it does, but may be confusing and/or mess up your destructor's close-down logic.
Other than that, go for it.
Is it bad practice to call an observer in a destructor?
No. It is not.
But it opens up potential for many pitfalls so make sure you do it without violating of C++ rules (C++ standard). In particular:
make sure exception are handled so that no exception will propagate out of destructor

Any reasons to use a a method instead of the class own destructor to clean up in C++?

Recently I am following the tutorials on rastertek and find that they suggest use a Shutdown() method for cleaning up instead of the class own destructor.The reason they mention is that the destructor is not guaranteed to be executed when calling some unsafe function like ExitThread().
However, I doubt if that method would get executed when even the destructor cannot be called. Indeed you can always call Shutdown() before you call ExitThread() but why not the same for the destructor? If I can do something before calling ExitThread(), I can certainly call the destructor as well.
Isn't placing the clean up code in the destructor more or less safer than using another method to do the trick? I know that releasing some vital resources like closing a file may need this separate method to do the trick. But are there any reasons other than that since this does not seem to be the case in the tutorials?
For the record, I know there is a similar question out there. But that one got no answer.
Isn't placing the clean up code in the destructor more or less safer than using another method to do the trick?
The problem here is that while ExitThread (and other functions like it) is a perfect API for C, with C++ code, it breaks stack unwinding.
The correct solution for C++ is to make sure you do not call ExitThread (and such) in code using anything with destructors.
Problem:
void thread_function()
{
raii_resource r { acquire_resource() };
ExitThread();
// problem: r.~raii_resource() not called
}
The shutdown solution:
void thread_function()
{
raii_resource r { acquire_resource() };
r.shutdown(); // release resources here
ExitThread();
// r.~raii_resource() still not called
}
The shutdown solution is not obvious at all in client code. As #stefan said, kill it with fire.
Better solution (than the Shutdown thing):
void thread_function()
{
{ // artificial scope where RAII objects live
raii_resource r { acquire_resource() };
}
// this space does not support RAII life
ExitThread();
}
RAII works fine here, but the artificial scope is not very elegant. On top, it's as inelegant as the shutdown solution (it requires a non-obvious artifice in client code).
Better (cleaner) solution:
template<typename F>
void run_thread(F functor)
{
functor(); // all RAII resources inside functor; this is simple and
// obvious from client code
ExitThread();
}
The only advantage to moving initialization out of the constructor, and for removing cleanup out of the destructor is when you've got a base class framework where you want to reliably call virtual methods during these stages.
Since the vtable is changing during construction/destruction calls to virtual functions don't resolve to the most derived instance. By having explicit Initialize/Shutdown methods you can be sure the virtual functions dispatch correctly.
Please note, this isn't an answer that advocates this approach, just one that is trying to work out why they've suggested it!
destructors are guaranteed to be called when an object is destroyed however thread clean up can require a tad more than just object destruction. Generally speaking cleanup methods are added when you need to handle releasing of shared resources, dealing with ancient libraries, etc.
Specifically you're dealing with the Win32 API which qualifies as an ancient c-style library considering ExitThread has been around longer than I have ...
With such approach you'll need to call Shutdown in all cases where the object should be destroyed - each time when it leaves the scope. In the case of exceptions (if they are used) you'll cannot call it. Destructor will be called automatically in these cases.
"I can certainly call the destructor as well" - calling the destructor explicitly is highly not recommended because it will be called automatically in any case. This should be avoided except only in special cases. If you mean this code from the tutorial:
System->Shutdown();
delete System;
then I don't see the difference because delete System; will call the destructor anyway.
In any case I would prefer
{
// work with System
...
}
mentioned in #utnapistim answer. I do not see any minuses in such way of coding, and also it is common way to specify scope. Even not going deep in the details of legacy ::ExitThread you gain auto cleanup. It is possible to work with WinApi with C++ RAII technique, look for instance at my code: multithreading sample project. Initial commit was bare WinAPI, and next commit introduced resource wrappers. You can compare both variants - second is much clearer, imho.

Is it safe to emit a sigc++ signal in a destructor?

My current project has a mechanism that tracks/proxies C++ objects to safely expose them to a script environment. Part of its function is to be informed when a C++ object is destroyed so it can safely clean up references to that object in the script environment.
To achieve this, I have defined the following class:
class DeleteEmitter {
public:
virtual ~DeleteEmitter() {
onDelete.emit();
}
sigc::signal<void> onDelete;
};
I then have any class that may need to be exposed to the script environment inherit from this class. When the proxy layer is invoked it connects a callback to the onDelete signal and is thus informed when the object is destroyed.
Light testing shows that this works, but in live tests I'm seeing peculiar memory corruptions (read: crashes in malloc/free) in unrelated parts of the code. Running under valgrind suggests there may be a double-free or continued use of an object after its been freed, so its possible that there is an old bug in a class that was only exposed after DeleteEmitter was added to its inheritance hierarchy.
During the course of my investigation it has occured to me that it might not be safe to emit a sigc++ signal during a destructor. Obviously it would be a bad thing to do if the callback tried to use the object being deleted, but I can confirm that is not what's happening here. Assuming that, does anyone know if this is a safe thing to do? And is there a more common pattern for achieving the same result?
The c++ spec guarantees that the data members in your object will not be destroyed until your destructor returns, so the onDelete object is untouched at that point. If you're confident that the signal won't indirectly result in any reads, writes or method calls on the object(s) being destroyed (multiple objects if the DeleteEmitter is part of another object) or generate C++ exceptions, then it's "safe." Assuming, of course, that you're not in a multi-threaded environment, in which case you also have to ensure other threads aren't interfering.

Network connection setup in constructor: good or bad?

I'm working on a class that handles interaction with a remote process that may or may not be available; indeed in most cases it won't be. If it's not, an object of that class has no purpose in life and needs to go away.
Is it less ugly to:
Handle connection setup in the constructor, throwing an exception if the process isn't there.
Handle connection setup in a separate connect() method, returning an error code if the process isn't there.
In option 1), the calling code will of course have to wrap its instantiation of that class and everything else that deals with it in a try() block. In option 2, it can simply check the return value from connect(), and return (destroying the object) if it failed, but it's less RAII-compliant,
Relatedly, if I go with option 1), is it better to throw one of the std::exception classes, derive my own exception class therefrom, roll my own underived exception class, or just throw a string? I'd like to include some indication of the failure, which seems to rule out the first of these.
Edited to clarify: The remote process is on the same machine, so it's pretty unlikely that the ::connect() call will block.
I consider it bad to do a blocking connect() in a constructor, because the blocking nature is not something one typically expects from constructing an object. So, users of your class may be confused by this functionality.
As for exceptions, I think it is generally best (but also the most work) to derive a new class from std::exception. This allows the catcher to perform an action for that specific type of exception with a catch (const myexception &e) {...} statement, and also do one thing for all exceptions with a catch (const std::exception &e) {...}.
See related question: How much work should be done in a constructor?
Regarding throwing exceptions, its perfectly fine to create your own classes. As a hypothetical user I'd prefer if they derived from std::exception, or perhaps std::runtime_error (which allows you to pass an error string to the ctor).
Users who want to can catch your derived type, but the common idiom of:
try {
operation_that_might_throw ();
} catch (std::exception& e) {
cerr << "Caught exception: " << e.what() << endl;
}
will work for your new exception types as well as anything thrown by the C++ runtime. This is basically the Rule of Least Surprise.
If your connection object is effectively non-functional if the connection fails then it doesn't make sense to have the object exist if all its other methods will always do nothing or throw exceptions. For this reason I would perform the connect in a constructor and fail by throwing an exception (derived from std::exception) if this method fails.
However, you are right that clients of the class may need to be aware that the constructor might block or fail. For this reason I might choose to make the constructor private and use a static factory method (named constructor idiom) so that clients have to make an explicit MakeConnection call.
It is still the client's responsibility to determine if not having a connection is fatal to it, or whether it can handle an offline mode. In the former case it can own a connection by value and let any connection failure propogate to its clients; in the latter it can own the object via a pointer, preferably 'smart'. In the latter case it might choose to attempt construction of the owned connection in its constructor or it might defer it until needed.
E.g. (warning: code all completely untested)
class Connection
{
Connection(); // Actually make the connection, may throw
// ...
public:
static Connection MakeConnection() { return Connection(); }
// ...
};
Here's a class that requires a working connection.
class MustHaveConnection
{
public:
// You can't create a MustHaveConnection if `MakeConnection` fails
MustHaveConnection()
: _connection(Connection::MakeConnection())
{
}
private:
Connection _connection;
};
Here's a class that can work without one.
class OptionalConnection
{
public:
// You can create a OptionalConnectionif `MakeConnection` fails
// 'offline' mode can be determined by whether _connection is NULL
OptionalConnection()
{
try
{
_connection.reset(new Connection(Connection::MakeConnection()));
}
catch (const std::exception&)
{
// Failure *is* an option, it would be better to capture a more
// specific exception if possible.
}
}
OptionalConnection(const OptionalConnection&);
OptionalConnection& operator=(const OptionalConnection&);
private:
std::auto_ptr<Connection> _connection;
}
And finally one that creates one on demand, and propogates exceptions to the caller.
class OnDemandConnection
{
public:
OnDemandConnection()
{
}
OnDemandConnection(const OnDemandConnection&);
OnDemandConnection& operator=(const OnDemandConnection&);
// Propgates exceptions to caller
void UseConnection()
{
if (_connection.get() == NULL)
_connection.reset(new Connection(Connection::MakeConnection()));
// do something with _connection
}
private:
std::auto_ptr<Connection> _connection;
}
Don't connect from the constructor, a constructor that blocks is unexpected and bad API design.
Write a connect method and mark your class noncopyable. If you rely on instances being connected already, make the constructor private and write a static factory method to get pre-connected instances.
If the connection would take a long time, it is more reasonable to put the code in another method. Still, you can (and you should) use exceptions to inform the caller whether your connect() method has been successful or not, instead of returning error codes.
It is also more advisable to create a new exception class derived from std::exception instead of throwing plain data or even throwing other STL exceptions. You may also derive your exception class from a more specific description of your error (for example, deriving from std::runtime_error), but this approach is less common.
I think Option 1 is a better approach but you need to think how would you expect the consumer of the class to use this? Just the fact that they have wired it up is good enough to go ahead and connect (Option 1) or the fact they should have the option to call Connect() when they are good and ready (Option 2)?
RAII also supports the DRY principle (don't repeat yourself). However with Option 1 you need to ensure you Exception handling is spot on and you don't get into race conditions. As you know, if there is an exception thrown in the constructor the destructor wont be called to clean up. Also be vary of any static functions you might have as you will need locks around those as well - leading you down a spiral path.
If you haven't seen this post yet its a good read.
I would go with the second one, since I believe that the constructor should not do any other thing than initialize the private members. Besides that, it's easier to deal with failures (such as not connecting). Depending on what you're exactly going to do, you could keep the object alive and call the connect method when you need it, minimizing the need of creating another object.
As for the exceptions, you should create your own. This will allow the caller to take specific rollback actions when needed.
Under the RAII mind of thought, isn't this by definition good? Acquisation is Initialization.
Another thing that was unclear in my original post is that the client code doesn't have any interaction with this object once it's connected. The client runs in its own thread, and once the object is instantiated and connected, the client calls one method on it that runs for the duration of the parent process. Once that process ends (for whatever reason), the object disconnects and the client thread exits. If the remote process wasn't available, the thread exits immediately. So having a non-connected object lying around isn't really an issue.
I found another reason not to do the connection in the constructor: it means that I either have to handle teardown in the destructor, or have a separate disconnect() call with no separate connect() call, which smells funny. The teardown is non-trivial and might block or throw, so doing it in the destructor is probably less than ideal.
I believe there is a pattern we can use here that addresses some of the points made in other answers. The question is pretty old but this was my first google result.
If the class is useless without a connection, then instantiating it conceptually appears to be half true. The object is not really ready to be used.
The user needs to separately call a connect() method. This just feels like bureaucracy.
Conversely, it is also true that a blocking operation is unconventional, and as other answers point out, may cause confusion. Not to mention annoyances in unit testing and threading.
I believe the pattern for this that addresses our problems is:
We can separate our functionality into more classes. The ready-to-go connection, the class that uses the connection and a factory.
The constructor needs the connection because it can't work without it.
Use a factory that sets up the connection to save the caller some work.
Our factory can be instantiated as empty (which makes sense). Then we can retrieve our class using it.
For example an FTPServer (not in C++ sorry)
class FTPServerFactory:
def get_with_environ_variables() -> FTPServer:
# create your connection here e.g. with FTP login details
class FTPServer:
def __init__(ftp_host: FTP_Host): #logged in an ready to go
There are two distinct benefits of this
Testing - we can easily mock a logged-in ftp_host to return whatever we want. This is way less confusing than having to reach into the class's constructor or the connect() method. We won't need to
Defining different ways of connecting using methods e.g. with env variables or user input