Jeroen
Jeroen

Reputation: 16815

How to stop a destructor from being called on a stack allocated object?

I have a union-like class with a member that may or may not be garbage depending on a boolean flag also set in that same class.

Obviously, I do not want that garbage to be destructed when my class goes out of scope. How to prevent a class member from being destructed?

I know this could be achieved with pointers and dynamically allocated memory, but I am looking for a more simple solution.

class MyContainer {
    bool has_child;
    MyChild child;

public:
    MyContainer(MyChild child) { this->has_child = true; this->child = child; }
    MyContainer() { this->has_child = false; }

    ~MyContainer() {
        if (!this->has_child) {
            // What to do here?
        }
    }
}

Upvotes: 4

Views: 341

Answers (2)

skypjack
skypjack

Reputation: 50540

I'm not that sure I would recommend it, but you can use placement new in a correctly sized array to do that.
As a minimal, working example:

#include<iostream>

struct MyChild {
    ~MyChild() { std::cout << "destructor" << std::endl; }
};

class MyContainer {
    bool drop;
    char arr[sizeof(MyChild)];
    MyChild *child;

public:
    MyContainer(bool drop)
        : drop{drop}, child{::new(&arr) MyChild{}}
    {}

    ~MyContainer() {
        if (drop) { child->~MyChild(); }
    }
};

void f() {
    std::cout << "f" << std::endl;
    MyContainer cont{true};
}

void g() {
    std::cout << "g" << std::endl;
    MyContainer cont{false};
}

int main() {
    f();
    g();
}

As you can see, destructor of MyChild is called only within f. Within MyContainer, whenever you want to access the instance of MyChild, you can do that through the child data member. And, of course, it's not dynamically allocated.

Upvotes: 2

songyuanyao
songyuanyao

Reputation: 172894

You can use std::optional (since C++17), which won't cause dynamic memory allocation. e.g.

class MyContainer {
    bool has_child;
    std::optional<MyChild> child;

public:
    MyContainer(MyChild child) : child(child) { this->has_child = true; }
    MyContainer() { this->has_child = false; }

    ~MyContainer() { /* nothing special need to do */ }
};

BTW: The member has_child could be replaced by std::optional::has_value().

Upvotes: 5

Related Questions