Maurycyt
Maurycyt

Reputation: 718

Avoid object destruction when initializing in local scope, C++

I am working on a networking project and I need to initialize an object in a try-catch block. I want the object, which represents a socket, to close the socket upon destruction, but I must avoid closing a socket before using it. A socket is represented with something as simple as an integer value which is why closing it is very easy, or rather hard to avoid.

In essence, I have the following (simplified) code:

#include <iostream>

using namespace std;

struct Foo {
    int v;

    Foo() {
        cerr << "Foo default constructor with v = " << v << ".\n";
    }

    Foo(int newV) : v(newV) {
        cerr << "Foo constructor with v = " << v << ".\n";
    }

    ~Foo() {
        cerr << "Foo destructor with v = " << v << ".\n";
    }
};

int main()
{
    Foo foo;
    try {
        foo = Foo(3);
    } catch (...) {
        // handle exception
    }
}

which yields the following output:

Foo default constructor with v = 0.
Foo constructor with v = 3.
Foo destructor with v = 3.
Foo destructor with v = 3.

This is a problem for me, because Foo has been destroyed twice with the value 3. Once, at the end of the program, and once after exiting the try block after an assignment operation.

My question is: can I instantiate an object by destroying its default value and constructing it in-place, instead of constructing another object and performing an assignment?

Of course, there are workarounds like using new, but I do not want to be forced to dereference an object everywhere and also I want to make sure it gets destroyed in case of an error (although of course for that I could use some pointer wrapper). I also do not want to use some separate C-style initialization method because I consider that ugly. I also have other members inside my "Foo" class, so I would need to perform some sort of destruction during assignment, which is inconvenient. Ideally, I'd love to see something akin to

Foo foo;
try {
    Foo foo(3);
} catch (...) {
    // handle exception
}

but I cannot do that because that leads to a redeclaration, or rather a shadow-declaration and on top of that, the more-local Foo object will be destroyed anyway.

Upvotes: 0

Views: 75

Answers (1)

Maurycyt
Maurycyt

Reputation: 718

I thought of this just when I was finishing typing up the question. Use move-assignment.

Take the original code and add the following method to the class definition:

Foo & operator=(Foo && other) {
    swap(v, other.v);
    return *this;
}

This way, when constructing an object only to assign it to some other object, this method will be called and it will simply swap the values in the v members. The other object will be immediately destroyed, but with the "old" value of v.

Take care to assign some meaningless value to v by default, perhaps -1.

Now, the output of the program is

Foo default constructor with v = 0.
Foo constructor with v = 3.
Foo destructor with v = 0.
Foo destructor with v = 3.

which is exactly what I was looking for.

Upvotes: 1

Related Questions