google / google/bigwheels

Remove (or reduce use of) ObjPtr and ObjPtrRef

Open
#572 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
107
Forks
42
PR merge metrics
No merged PRs in 30d

Description

Use of `ObjPtr` should be replaced with T*, and `ObjRefPtr` should be replaced with T** to avoid subtle bugs.

In #565, `&GetSwapchain()->GetPresentationReadySemaphore(imageIndex))` is bad since I'm taking the address-of an rvalue. This leads to stack-use-after-scope: at the end of the line, the SemaphorePtr (`ObjPtr`) returned by GetPresentationReadySemaphore goes out of scope; however, I captured a reference to the value inside the SemaphorePtr (via the address-of operator) which is now invalid.

This was allowed since `ObjPtr` overloads the address-of operator (`operator&`). Normally, `&ObjPtr` would give me a `ObjPtr*`. However, given the overload, I get the `T*` contained inside the class. The compiler didn't stop me from doing so. In normal cases, however, it would. Consider:

```c++
int i = 0;

int** i_ptr = &(&i);
// Clang: error: cannot take the address of an rvalue of type 'int *
// gcc: error: lvalue required as unary '&' operand

// This makes sense because &i doesn't have a memory address yet.
// How can we have an address of something that doesn't have an address?
```

However, here, it doesn't:

```c++
// Pared-down version of ObjPtrRef
template
class PtrRef {
public:
PtrRef(T* ref) : ref(ref) {};

operator T**() {
return ref;
}

T** ref;
};

// Pared-down version of ObjPtr
template
class Ptr {
public:
Ptr(T* me) : me(me) {};

T** operator&() { // DANGER!
return &me;
}

T* me;
};

int i = 0;

int** i_ptr = &Ptr(&i);
// no error but incorrect behavior
// by now, Ptr has been destroyed.
// That means Ptr.me is invalid, as is ref = &me
```

Note that Google Style says:

> Do not overload &&, ||, , (comma), or unary &.
>
> \- https://google.github.io/styleguide/cppguide.html#Operator_Overloading

There are a variety of options, each more involved than the last:

1. New functions should prefer returning T* or T** instead of ObjPtr or ObjPtrRef
2. Remove `operator&` from ObjPtr in favor of an explicit `.get()` function that returns T*. This is what smart pointers (`unique_ptr`, `shared_ptr`) do. Since they return a T*, the compiler will catch mistakes.
3. Remove ObjPtr entirely. This might be easier than expected since mostly the aliases are used rather than ObjPtr itself.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.