Willy Goat
Willy Goat

Reputation: 1203

Does an std::optional parameter create a copy?

I have a function that takes an std::optional

void foo(const std::optional<T>& opt);

But copying T is expencive.

Does this create a copy of T?

If so, how can I not create a copy?

Upvotes: 8

Views: 11184

Answers (3)

opetroch
opetroch

Reputation: 4105

I think you will find useful this documentation page. See the section about "Optional function parameters".

When you call the function and pass an instance of T, an optional will be constructed which will own its own copy of T, therefore it will call T's copy constructor.

int main()
{
  T t;
  optional<T> ot;
  foo(t);  // will create a copy
  foo(ot); // won't create a copy
}

If you're using boost::optional, not std::optional, you can declare foo as receiving an optional reference, i.e.

void foo(boost::optional<const T&> t)

Upvotes: 4

geofflee
geofflee

Reputation: 3791

Yes, std::optional stores a copy of whatever you pass to it. The C++17 standard explicitly prohibits storing references in std::optional. See: https://en.cppreference.com/w/cpp/utility/optional#:~:text=There%20are%20no%20optional%20references

As suggested by others, passing std::optional<std::reference_wrapper<const T>> is one way to avoid making copies.

void foo(const std::optional<std::reference_wrapper<const T>>& opt) {
  if (opt) {
    // Do something.
  }
}

T t;
foo(t);

But consider that the C++ committee had good reasons for disallowing references in std::optional. For instance, an "optional reference" essentially describes what a plain pointer does, and plain pointers don't suffer from the long type name.

void foo(const T* opt) {
  if (opt) {
    // Do something.
  }
}

T t;
foo(&t);

Upvotes: 8

Marko Popovic
Marko Popovic

Reputation: 4153

As clarified by your follow up comment, you are calling the function foo like this:

T t;
...
foo({t});

In this case, the answer is yes. A copy of t will be created. To avoid that, you can use std::reference_wrapper to avoid copying:

void foo(const std::optional<std::reference_wrapper<const T>> &optT) {
    ...
}

With these changes to the function, calling the it in the same manner will not result in creation of a copy.

Upvotes: 4

Related Questions