Suppose I have this struct
struct MyStruct {
static MyStruct Create(int x) {
return { x*2, x>3 };
}
MyStruct(const MyStruct& c) = delete; // no copy c'tor
private:
MyStruct(int a_, bool b_) : a(a_), b(b_) {} // private c'tor -- can't use new
const int a;
const bool b;
};
Edit: I deleted the copy constructor. This is simplified example of some classes I have in my codebase where they don't have copy c'tors.
I can get an instance on the stack like so:
int main() {
auto foo = MyStruct::Create(2);
return 0;
}
But suppose I need a pointer instead (or unique_ptr
is fine), and I can't change the implementation of MyStruct
, how can I do that?
CodePudding user response:
Is this what you're looking for?
auto baz = std::make_unique<MyStruct>( MyStruct::Create(2) ); // unique pointer
CodePudding user response:
You could wrap MyStruct
in another class, which has a MyStruct
member. Here's a minimal version of that:
class Wrapper {
public:
MyStruct ms;
Wrapper(int x) : ms(MyStruct::Create(x)) { }
};
which you can use like so:
int main() {
MyStruct::Create(2);
std::make_unique<Wrapper>(2);
}
I think this shouldn't be making any copies nor moves.
You can then add any other constructors and methods you like, possibly forwarding some of the method calls to ms
. Some might choose to make ms
protected or private.
If you're wondering why no copies are made - that's due to copy elision:
What are copy elision and return value optimization?
CodePudding user response:
A comment rather than an answer, to avoid confusion for future readers.
I can get an instance on the stack like so:
int main() { auto foo = MyStruct::Create(2); return 0; }
Note that this is only true as of C 17 and guaranteed copy elision, whereas the program is ill-formed is C 14, as even if the copy may be elided, the initialization of foo
is copy-initialization from a temporary (in C 17: the temporary is never materialized).
CodePudding user response:
One more way to do it:
struct ChildStruct : public MyStruct {
ChildStruct(int x) : MyStruct(MyStruct::Create(x))
{}
};
int main() {
MyStruct *foo1 = new ChildStruct(2);
return 0;
}
CodePudding user response:
C style solution. I am not sure that this is not UB, but for simple struct with 2 integer fields it should work.
int main() {
auto foo = MyStruct::Create(2);
MyStruct *p = (MyStruct*)malloc(sizeof(MyStruct));
memcpy(p, &foo, sizeof(MyStruct));
//...
free(p);
return 0;
}