duong_dajgja
duong_dajgja

Reputation: 4276

Is calling a class member function which does some clean-up stuff on member variables safe if constructor throws?

I have the below code snippet which is to demonstrate use-case of function-try-block for constructor. Because the constructor of Controller throws no object of it gets created successfully, i.e. the client_ member variable should no longer exist too when exception is thrown, is that correct? If so then is that safe to call deinit() which is to clean-up the client_? If not safe, say if client_ was a raw pointer which then how would I catch the exception and do clean-up stuff for it?

class Client {
 public:
  Client() { std::cout << "Client()" << std::endl; }
  ~Client() { std::cout << "~Client()" << std::endl; }
  void Start() { throw "Start() failed with exception"; }
};

class Controller {
 private:
  std::shared_ptr<Client> client_;

 public:
  Controller() try {
    client_ = std::make_shared<Client>();
    client_->Start();
  } catch (...) {
    deinit();
  }

  ~Controller() {
    deinit();
  }

 private:
  void deinit() {
    if (client_) {
      client_.reset();
    }
  }
};

Upvotes: 0

Views: 81

Answers (1)

Sam Varshavchik
Sam Varshavchik

Reputation: 118415

the client_ member variable should no longer exist too when exception is thrown, is that correct?

No this is incorrect. The exception gets thrown after the client_ member of the new class instance gets constructed.

A class's constructor gets called only after all members of the new class instance get constructed; and the constructor's job is to do whatever it means to construct the class itself, after all the class members get constructed.

Once you're in the constructor, you're guaranteed that all the members of the new class instance are fully constructed. You can take that to the bank.

is that safe to call deinit()

Well, it's "safe" since it's defined behavior. But, in this case, it is completely unnecessary. If an exception gets thrown in the constructor, all constructed members of the new class instance get automatically destroyed, in reverse construction order. client_ will get destroyed normally, as if it would if the class fully constructed and then destroyed at some point later.

if client_ was a raw pointer which then how would I catch the exception and do clean-up stuff for it?

Pretty much the way the shown code does it. But it is not a raw pointer, but a shared_ptr, which handles this.

Upvotes: 1

Related Questions