C++ Logo

std-proposals

Advanced search

A new qualifier for "uniquely referable" object

From: Omer Rosler <omer.rosler_at_[hidden]>
Date: Thu, 18 Mar 2021 18:59:32 +0200
 Proposal idea:
A keyword (bikeshedding - `unique_referable`) for declaring that there is
only one way to refer to an object throughout its lifetime.

This has the following benefits:

1. Allow more aggressive copy elision rules:
```c++
pair<non_copyable, int> mrv_function()
{
    unique_referable non_copyable a = {};
    //fill a
    return {a, 42}; //OK: copy elision is mandatory here
}
```
The rules to allow this are completely analogous to `prvalue`
materialization conversion, only we delay materialization for an lvalue.


2. Prevent dangling references.
```c++
int& get_dangling()
{
    unique_referable int a = 42;
    return a; //Compile error: Can't bind reference to uniquely referable
object
}
```

3. Help compiler escape analysis:
```c++
extern void foo( unique_referable int& ref);
int bar()
{
    unique_referable int a = 42;
    foo(a); // OK: in `foo`, the unique way to refer to the underlying
object is through `ref`
    return a; //Mandatory copy elision
}
```

4. Allow destructive moves
```c++
struct A
{
    A( unique_referable A&&a) = default;
};
```
This move is always destructive because `a` is the unique way to access the
underlying object and is an rvalue-reference, therefore this move is always
destructive.

Possible extensions:
1. We might need a new form of reference to work with `unique_referable`
objects.
For example:
```c++
extern void foo( unique_referable int& a, unique_referable int & b);
struct A {int a, b;};
void bar()
{
    unique_referable A var{1,2};
    foo(var.a, var.b); //OK
    foo(var.a, var.a); //UB
}
```
I think the semantics of such references should be similar to the ones in
structured-bindings

2. If we allow a syntax that overloads on `unique_referable`ness, we can
practically achieve lazy evaluation as a language construct.

```c++
struct A
{
    bool called_lazily = false;
    int foo() unique_referable
    {
        //lazily update
        called_lazily = true;
        return 42;
    }

    int foo()
    {
        return 0;
    }

    constexpr operator A&() unique_referable& //materialization conversion
    {
        if ( called_lazily )
        {
            //do something now
        }
        return *this;
    }
};

A bar()
{
    unique_referable A a;
    std::cout << a.foo(); //prints 42
    return a;
}

bool baz()
{
    unique_referable A a = bar(); //Copy elided
    return a.called_lazily; //Calls the materialization conversion before
this line
}
```

What do you think of the idea?

Received on 2021-03-18 11:59:46