Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RAII and exception in constructor

Imagine that I have a job to do, which can be done in three different ways: a slow and painful, but failsafe way; the way with moderate suffering, given you have Resource1; and a quick and easy way, which requires both Resource1 and Resource2. Now, those resources are precious so I wrap them up into RAII-implementing ResNHolders and write something like this:

void DoTheJob(Logger& log/*, some other params */) {
    try {
        Res1Holder r1(/* arguments for creating resource #1 */);
        try {
            Res2Holder r2(/* arguments */);
            DoTheJobQuicklyAndEasily(log, r1, r2);
        }
        catch (Res2InitializationException& e) {
            log.log("Can't obtain resource 2, that'll slowdown us a bit");
            DoTheJobWithModerateSuffering(log, r1);
        }
    }
    catch (Res1InitializationException& e) {
        log.log("Can't obtain resource 1, using fallback");
        DoTheJobTheSlowAndPainfulWay(log);
    }
}

"DoTheJobXxx()" take references to Logger/ResNHolder, because they are non-copyable. Am I doing it too clumsily? Is there any other clever way to structurize the function?

like image 255
Joker_vD Avatar asked Sep 25 '13 16:09

Joker_vD


1 Answers

I think your code would be just fine, but here is an alternative to consider:

void DoTheJob(Logger &log/*,args*/)
{
    std::unique_ptr<Res1Holder> r1 = acquireRes1(/*args*/);
    if (!r1) {
        log.log("Can't acquire resource 1, using fallback");
        DoTheJobTheSlowAndPainfulWay(log);
        return;
    }
    std::unique_ptr<Res2Holder> r2 = acquireRes2(/*args*/);
    if (!r2) {
        log.log("Can't acquire resource 2, that'll slow us down a bit.");
        DoTheJobWithModerateSuffering(log,*r1);
        return;
    }
    DoTheJobQuicklyAndEasily(log,*r1,*r2);
}

Where the acquireRes functions return a null unique_ptr when the resource fails to initialize:

std::unique_ptr<Res1Holder> acquireRes1()
{
  try {
    return std::unique_ptr<Res1Holder>(new Res1Holder());
  }
  catch (Res1InitializationException& e) {
    return std::unique_ptr<Res1Holder>();
  }
}

std::unique_ptr<Res2Holder> acquireRes2()
{
  try {
    return std::unique_ptr<Res2Holder>(new Res2Holder());
  }
  catch (Res2InitializationException& e) {
    return std::unique_ptr<Res2Holder>();
  }
}
like image 121
Vaughn Cato Avatar answered Oct 09 '22 19:10

Vaughn Cato