1

I have 3 classes, Fruit, Apple and Orange, with Fruit being the parent of both. I have a static method where I do the following:

int32_t Fruit::frutificate(const Settings& settings) {
  Fruit listener;
  if (settings.has_domain_socket()) {
    listener = Apple(settings);
  } else {
    listener = Orange(settings);
  }
  return uv_run(listener.loop, UV_RUN_DEFAULT);
}

What confuses me is that the destructor of Apple, which runs clean up code Fruit doesn't have, is called within the condition. Apple is a child of Fruit and Fruit is declared outside the condition so shouldn't the scope last until the return?

Barry
  • 286,269
  • 29
  • 621
  • 977
ruipacheco
  • 15,025
  • 19
  • 82
  • 138
  • 8
    `Apple's` destructor would be called at the end of this line: `listener = Apple(settings);`. The RHS is a temporary that gets discarded after a *conversion* to `Fruit`. Also, look up *object slicing*. – juanchopanza Jan 28 '15 at 12:42
  • You probably want to make `Fruit listener` a pointer (unless you have defined conversion operators for Apples and Oranges into Fruit). – Galik Jan 28 '15 at 12:44
  • 1
    One might add that the remedy is to use a pointer or a reference. – Peter - Reinstate Monica Jan 28 '15 at 12:45

1 Answers1

6

You are creating a temporary of type Apple. It goes out of scope at the end of the expression that it is a part of - which is the assignment statement. When it goes out of scope, the destructor will get called. The hierarchical relationship between Fruit and Apple is irrelevant here.

If it helps, you can think of this block:

if (settings.has_domain_socket()) {
    listener = Apple(settings);
}

as basically equivalent to:

if (settings.has_domain_socket()) {
    Apple some_temporary_apple(settings);
    listener = std::move(some_temporary_apple);
}

which may make it clearer as to why ~Apple() gets called at the end of the assignment.

Also note that:

Fruit f = Apple();

will perform object slicing, which makes it an anti-pattern.

Community
  • 1
  • 1
Barry
  • 286,269
  • 29
  • 621
  • 977
  • 1
    Object Slicing - thanks, this turns out to be a bigger problem. – ruipacheco Jan 28 '15 at 13:10
  • 1
    @lapinrigolo Yes. The type of polymorphism you want requires the use of pointers – Félix Cantournet Jan 28 '15 at 13:12
  • @FélixCantournet That is incorrect: the type of polymorphism laprinrigolo is doing does not require pointers. It cannot be done with values, but references are neither pointers nor values. Sadly, it led the OP down a [bad path](https://stackoverflow.com/questions/28194024/destructor-not-being-called-with-smart-or-raw-pointer/28194561#28194561) – Yakk - Adam Nevraumont Jan 28 '15 at 14:25
  • @Yakk Yes, references could be used too (and preferably in this particular instance). I think the larger point was beware of object slicing. – Félix Cantournet Jan 28 '15 at 14:40