Skip to content

Instantly share code, notes, and snippets.

@graphitemaster
Last active March 8, 2016 07:52
Show Gist options
  • Select an option

  • Save graphitemaster/618b646a3f5ed4fbaab6 to your computer and use it in GitHub Desktop.

Select an option

Save graphitemaster/618b646a3f5ed4fbaab6 to your computer and use it in GitHub Desktop.
C++ "new auto" proposal

Proposal: "new auto"

Exibit:

class A {
    A();
    T *a;
};

Need to know type of `a' here to call new

A::A() : a(new T) { }

Imagine the class member type changes but implementing code stays the same, thus it allocates an incorrect amount of memory for the object and calls the wrong constructor. How do we solve this?

A::A() : a (new typename remove_reference<decltype(A::a)>::type) { }

Not that pretty but does handle this case. What's interesting is in these contexts the compiler knows the type from the lvalue.

T *a = new T;
T *b(new T);

We can see this is true with container types too:

unique_ptr<T> a = make_unique<T>(...);
unique_ptr<T> b(new T(...));

shared_ptr<T> c = make_shared<T>(...);
shared_ptr<T> d(new T(...));

Lets review our original example now with "new auto"

A::A() : a(new auto) { }

Changes of the class member type does not break the implementing code, "auto" knows the type.

Consistent with other forms

T *a = new auto;
T *a(new auto);

Ambiguous with current C++ however:

new auto(expr) already exists in C++, it's such that new allocates and constructs for type of "expr" with value "expr".

We argue this behavior is inconsistent with the rest of the language as auto is treated as a non-type and as a function-style cast here.

With explicit initialization this would be preferred behavior of the syntax, which shouldn't break anything either.

T *a = new auto(...); 
T *a(new auto(...));

What we obtain is improved visibility for containment and consistency with respect to auto and other language rules.

For example make_unique and make_shared can be made much simpler and better

template <typenmame T, typename A...>
unique_ptr<T> make_unique(A&&... a) {
  return { new auto(forward<A>(a)...) };
}

template <typename T, typename A...>
shared_ptr<T> make_shared(A&&... a) {
  return { new auto(forward<A>(a)...) };
}

Now make_unique and make_shared can access private constructors, since auto avoids the visibility problem in this construct.

class A {
  A() { ... }
public:
  void x() { auto x = make_unique<A>(); ... } // Works!
};

auto x = make_unique<A>(); // Does not work since private (as expected)

Oh yes it works for arrays too

int *x = new auto[10]; // 10 integers (uninitialized)
int *y = new auto[10](100); // 10 integers (initialized to 100)
auto x = make_unique<int[]>(10); // 10 integers (uninitialized)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment