1
class ScopedClass {
 public:
  ScopedClass() {
    cout << "constructor called\n";
  }

  ~ScopedClass() {
    cout << "destructor called\n";
  }

  ScopedClass(const ScopedClass &t)
  {
      cout << "copy constructor called\n";
  }

  ScopedClass(ScopedClass &&t)
  {
      cout << "move constructor called\n";
  }
}

std::optional<ScopedClass> check_and_return(bool condition) {
  if (condition == true)
    return std::make_optional(ScopedClass());
  return std::nullopt;
}

int main() {
  auto x = check_and_return(true);
}

I want a single ScopedClass object but ScopedClass() is copied/moved when I enclose it within std::optional. This means that the destructor is called when it's copied/moved and it's being called twice. Once inside check_and_return and once when main ends.

I would like the destructor to be called only when main ends.

Is there a way to achieve this? Or some alternate method not using std::optional?

2
  • 1
    What is your problem with moving? Do you have a proven performance problem with your code when you use std::optional?. I ask because as far as I know std::optional is quite good at avoiding making copies. Commented Dec 13, 2023 at 16:37
  • 6
    Do you want just std::make_optional<ScopedClass>()? Your code is creating a temporary ScopedClass which is moved into the optional, this defeats the purpose of using make_optional Commented Dec 13, 2023 at 16:38

2 Answers 2

7

You can use the in-place overload of std::make_optional rather than the move overload.

std::optional<ScopedClass> check_and_return(bool condition) {
  if (condition == true)
    return std::make_optional<ScopedClass>(); // constructs ScopedClass in place with the arguments ()
  return std::nullopt;
}
Sign up to request clarification or add additional context in comments.

Comments

3

And yes there is another option, use std::make_unique/std::unique_ptr. This will not move anything and call constructor and destructor only once.

#include <cassert>
#include <memory>
#include <iostream>
#include <string>

class ScopedClass {
public:
    ScopedClass() {
        std::cout << "constructor called\n";
    }

    ~ScopedClass() {
        std::cout << "destructor called\n";
    }

    ScopedClass(const ScopedClass& t)
    {
        std::cout << "copy constructor called\n";
    }

    ScopedClass(const ScopedClass&& t)
    {
        std::cout << "move constructor called\n";
    }

private:
    std::string some_resource;
};

std::unique_ptr<ScopedClass>  check_and_return(bool condition)
{
    if ( condition )
    {
        return std::make_unique<ScopedClass>();
    }

    return nullptr;
}

int main() 
{
    auto x = check_and_return(true);
}

3 Comments

Only downside (just lazy reason) for this method. We must check return value with if(x != nullptr) not if(x) like std::optional
Not if(x) is ok. std::unique_ptr has an implicit bool conversion, that's why I proposed this solution. Also the way I understand it no function calls will be made on ScopedClass (the name seems to imply some RAII resource managment). If call needs to be made the std::optional code would also have to have the if (x) code.
Thank you. I used to use if (x) for check value for std::unique_ptr but it's got unexpected result. I might did something wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.