Date: Mon, 8 Aug 2022 11:59:41 +0100
On Thu, Jul 28, 2022 at 10:26 PM Marcin Jaczewski wrote:
>
> Image we add new contextual keyword like:
> ```
> class Type arg_destructor_in_callee
> {
> };
> ```
> Now when the function `void foo(Type arg)` is called, the object `arg`
> will be destroyed
> in the body of `foo` not by the caller. This will make for compiler
> easy to see if object was
> moved before the destructor call and then if the destructor was inlined
> then it could remove it all. This will work great with `bitcopies` or
> `Trivially Relocatable` types.
The following program can be toggled to "destroy in caller" or
"destroy in callee" by setting the global boolean "destroy_in_callee"
to true or false.
I realise that the following code won't give you the optimisation
you're looking for, but is it at least the behaviour you're going for?
// Step 1: Have a global boolean to specify destroy by caller/callee
bool constexpr destroy_in_callee = true;
#include <iostream>
// Step 2 : Write a sample dummy class that says hello and goodbye
struct MyClass {
bool is_valid = true;
MyClass(char const* = nullptr)
{
std::cout << "Constructing object" << std::endl;
}
MyClass(MyClass &&temp)
{
temp.is_valid = false;
}
~MyClass(void)
{
if ( false == is_valid ) return;
std::cout << "Destroying object" << std::endl;
}
};
// Step 3: Write a template function to get an L-value reference to a
// temporary object
template <class T>
T &LvalueRef(T &&arg)
{
return arg;
}
#include <optional>
// Step 4: Write a preprocessor macro to create a temporary
// object of type 'optional' from a temporary.
#define ARG(temp) LvalueRef(std::optional<decltype(temp)>( \
std::move(temp) ))
// Step 5: Write a function that can either do "destroy by caller"
// or "destroy by callee"
void SomeFunction(std::optional<MyClass> &arg)
{
// I have the choice now whether the string
// gets destroyed in this function or in
// the calling function.
if constexpr ( destroy_in_callee ) arg.reset();
}
int main(void)
{
// Step 6: Call the function and check where the temporary is destroyed
SomeFunction( ARG(MyClass(nullptr)) ),
(std::cout << "Hello again from Main" << std::endl);
std::cout << "Last line in body of Main" << std::endl;
}
This program will print either:
Constructing object
Hello again from Main
Destroying object
Last line in body of Main
or:
Constructing object
Destroying object
Hello again from Main
Last line in body of Main
>
> Image we add new contextual keyword like:
> ```
> class Type arg_destructor_in_callee
> {
> };
> ```
> Now when the function `void foo(Type arg)` is called, the object `arg`
> will be destroyed
> in the body of `foo` not by the caller. This will make for compiler
> easy to see if object was
> moved before the destructor call and then if the destructor was inlined
> then it could remove it all. This will work great with `bitcopies` or
> `Trivially Relocatable` types.
The following program can be toggled to "destroy in caller" or
"destroy in callee" by setting the global boolean "destroy_in_callee"
to true or false.
I realise that the following code won't give you the optimisation
you're looking for, but is it at least the behaviour you're going for?
// Step 1: Have a global boolean to specify destroy by caller/callee
bool constexpr destroy_in_callee = true;
#include <iostream>
// Step 2 : Write a sample dummy class that says hello and goodbye
struct MyClass {
bool is_valid = true;
MyClass(char const* = nullptr)
{
std::cout << "Constructing object" << std::endl;
}
MyClass(MyClass &&temp)
{
temp.is_valid = false;
}
~MyClass(void)
{
if ( false == is_valid ) return;
std::cout << "Destroying object" << std::endl;
}
};
// Step 3: Write a template function to get an L-value reference to a
// temporary object
template <class T>
T &LvalueRef(T &&arg)
{
return arg;
}
#include <optional>
// Step 4: Write a preprocessor macro to create a temporary
// object of type 'optional' from a temporary.
#define ARG(temp) LvalueRef(std::optional<decltype(temp)>( \
std::move(temp) ))
// Step 5: Write a function that can either do "destroy by caller"
// or "destroy by callee"
void SomeFunction(std::optional<MyClass> &arg)
{
// I have the choice now whether the string
// gets destroyed in this function or in
// the calling function.
if constexpr ( destroy_in_callee ) arg.reset();
}
int main(void)
{
// Step 6: Call the function and check where the temporary is destroyed
SomeFunction( ARG(MyClass(nullptr)) ),
(std::cout << "Hello again from Main" << std::endl);
std::cout << "Last line in body of Main" << std::endl;
}
This program will print either:
Constructing object
Hello again from Main
Destroying object
Last line in body of Main
or:
Constructing object
Destroying object
Hello again from Main
Last line in body of Main
Received on 2022-08-08 10:59:54