@coder777: I want to express that I'm moving the ownership of the "app" object into the function call. There is no more code after calling run(), because the run() method "consumes" the app object immediately after it is finished.
In C it's possible to do this:
|
AzApp_run(AzApp_create());
|
In this case the constructed AzApp object returned by AzApp_create() is directly passed (by-value) into the first argument slot of AzApp_run(), so that the object is consumed by the run() function. The "ownership" is immediately moved from the parent main() function into the run() function without any intermediate copies. The compiler can see this and optimize accordingly. This is the default in Rust (except for trivially-copyable types such as integers). In C++ you can annotate your class to use move constructors instead of copy constructors with:
1 2
|
/* tell C++ to use move constructor instead of copy constructor */
App (App&& a) noexcept = default;
|
This implicilty deletes the copy constructor, so then you HAVE to use std::move if you do anything with your object (which is good, std::move is usually better for performance). My problem in the code was that the "this" pointer is a "*App", but in order to invoke the C function I need a "App" object (i.e. not just the pointer).
I've figured out what the problem was: I just need to dereference the "this" pointer when using std::move, because std::move expects a rvalue instead of a prvalue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
#include <utility>
struct App {
void* ptr;
App() = delete;
/* tell C++ to use move constructor instead of copy constructor */
App (App&& a) noexcept = default;
public:
static App create();
int run();
};
extern "C" {
App AzApp_create();
int AzApp_run(App);
}
App App::create() {
return AzApp_create();
}
int App::run() {
return AzApp_run(std::move(*this)); /* std::move(*this) instead of std::move(this) */
}
int main() {
auto app = App::create();
return app.run();
}
|
@ne555: my example wasn't the actual API, I wanted to keep the example code as short as possible. The final code would then look something like this:
1 2 3 4 5 6 7 8 9 10 11
|
// ...
int App::run(const WindowCreateOptions&& window) {
return AzApp_run(this, std::move(window)); /* std::move(*this) instead of std::move(this) */
}
int main() {
auto window = WindowCreateOptions::default();
auto app = App::create();
return app.run(std::move(window));
}
|
So that should do it. Thanks!