Reputation: 718
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
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