Как перенести время жизни этого в другой объект в C ++? - PullRequest
0 голосов
/ 04 июля 2018

Я хочу смоделировать функции Rust bar(self, ...) в C ++, поэтому я пишу что-то вроде этого:

class Foo;

class Bar {
public:
    explicit Bar(unique_ptr<Foo> foo);
private:
    unique_ptr<Foo> _foo;
};

class Foo {
public:
    Bar bar() {
        return Bar(unique_ptr<Foo>(this));
    }
};

Bar::Bar(unique_ptr<Foo> foo) : _foo(move(foo)) {}

TEST_CASE("Convert a Foo object into a Bar object") {
    Bar b = Foo().bar();
}

Этот сегмент кода вызовет ошибку сегмента. Потому что Foo() и b оба думают, что они владеют экземпляром Foo, и он будет очищен дважды. Как это исправить?


Я опишу, что я хочу сделать. В следующем коде:

auto foo = unique_ptr<Foo>(new Foo());
Bar b = some_func(move(foo));

После вызова some_func время жизни foo "переносится" на some_func, и мы больше не можем использовать foo. Функция конвертора должна быть разработана таким образом, если b наследует ресурсы foo. В моей ситуации я бы хотел, чтобы some_func стал методом экземпляра foo. И это все.

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

Вы, похоже, путаете то, что делает std :: move, и предполагаете, что оно передает владение объектом. Это не так.

Все, что делает std :: move, конвертируется в ссылку rvalue, так что можно вызвать соответствующую функцию, которая принимает параметр ссылки rvalue.

Насколько мне известно, вы не можете продлить срок жизни объекта изнутри самого объекта. В приведенном вами примере вы создаете временный объект класса Foo, который будет уничтожен, как только вернется bar ().

Одна вещь, которую вы можете сделать, это объявить вашу функцию some_func для получения ссылки на rvalue, например:

Bar some_func(std::unique_ptr<Foo>&& someFoo)
{ 
   Bar someBar(std::move(someFoo));
   return someBar;
}

int main() {
   auto foo = std::make_unique<Foo>();
   //do stuff with foo
   Bar b = some_func(std::move(foo));
   //foo is now invalid, and can't be used;
   //b has ownership of foo
   return 0;
}

Я не уверен, что это отвечает на ваши вопросы и делает то, что вы ожидаете. Вывод заключается в том, что вместо создания временного объекта вы создаете объект с помощью make_unique и перемещаетесь по уникальному указателю на любой объект, которым вы хотите владеть своим экземпляром.

0 голосов
/ 04 июля 2018

Полагаю, вы хотите, чтобы эта строка из контрольного примера была действительной:

Bar b = Foo().bar();

И вы хотите, чтобы его эффект состоял в том, что b получает std::unique_ptr<Foo> для игры.

Если это так, вам придется реализовать bar, чтобы создать новый объект Foo, потому что Foo() - это временный объект, время жизни которого не может стать динамичным, как вам бы этого хотелось. Вы упомянули в комментариях, что Foo не может быть скопировано, но, вероятно, его можно переместить:

class Foo {
public:
    Bar bar() && {
        return Bar(std::make_unique<Foo>(std::move(*this)));
    }
};

Обратите внимание, что я сделал bar квалифицированным по rvalue, чтобы его нельзя было вызывать для lvalue (потому что он перешел из *this). Чтобы вызвать его по lvalue, вам нужно набрать move:

Foo().bar();  // rvalue calls are fine
Foo f;
std::move(f).bar();  // lvalue must be moved
...