By AUD_FOR_IUV


2018-07-11 23:05:41 8 Comments

If we take std::unique_ptr as an example, the prevailing wisdom for passing move-only types into a sink function (e.g. a constructor that takes ownership of the pointer) is to pass it in by value and move it at the call site. E.g.

class Sink {
    public:
        Sink(std::unique_ptr<Foo> foo) : foo(std::move(foo)) {}

    private:
        std::unique_ptr<Foo> foo;
};

How is this possible? Shouldn't the compiler be able to deduce immediately that std::unique_ptr is a move-only type and reject the use of Sink(std::unique_ptr<Foo>)? Is there something special about the pass-by-value rules here (i.e. that things passed by value are copied into that functions activation frame)?

Thanks in advance.

1 comments

@Henri Menke 2018-07-11 23:13:16

Of course this works, as long as you either pass an rvalue to the constructor of Sink or you move the argument. In both cases the move constructor, rather than the (deleted) copy constructor will be called for the argument.

N.B.: I don't think std::move is a good idea here because then you'll have a moved-from object floating around in your function. Static analysis can probably spot this but it's a source of bugs.

#include <memory>

struct Foo {};

class Sink {
    public:
        Sink(std::unique_ptr<Foo> foo) : foo(std::move(foo)) {}

    private:
        std::unique_ptr<Foo> foo;
};

int main() {
    // rvalue
    Sink s(std::make_unique<Foo>());

    // std::move (can be dangerous)
    auto f = std::make_unique<Foo>();
    Sink ss(std::move(f));

    // By value is not allowed
    auto ff = std::make_unique<Foo>();
  //Sink sss(ff); // BOOM!
}

Live on Wandbox

@Henri Menke 2018-07-11 23:17:41

@user4581301 Thank you for your comment but I'm not sure whether I understand it correctly. Please feel free to edit my answer for clarification.

@user4581301 2018-07-11 23:24:25

Your update explains what happened well enough for me.

@Yakk - Adam Nevraumont 2018-07-11 23:30:24

"moved-from object is undefined behaviour" no, that is false. There are ways to use moved-from objects that invoke UB, but the same is true of non-moved-from objects.

@Captain Giraffe 2018-07-11 23:36:26

moved-from objects are in a valid but indeterminate state.

@AUD_FOR_IUV 2018-07-11 23:45:16

So would it be more accurate to say that pass-by-value doesn't always invoke the copy constructor, but rather invokes either the copy or move constructor depending on whether the value passed in is an lvalue or rvalue reference?

@Henri Menke 2018-07-12 00:20:48

@AUD_FOR_IUV As you see it depends on the kind of value. Rvalues invoke the move constructor (if there is one, otherwise copy), lvalues invoke the copy constructor.

@AUD_FOR_IUV 2018-07-12 01:03:44

Wow that explains a lot. I had always been told that passing by value unconditionally invokes the copy constructor (because I guess that was the case pre-C++11) and never stopped to consider that the behavior might be different when move semantics come into play. Thanks!

@Yakk - Adam Nevraumont 2018-07-12 01:15:02

"the state of a moved-from object is indeterminate" this is also false. There are moved-from objects with indeterminate state, but there are also not-moved from objects with indeterminate state, and moved-from objects (both inside, and outside of std) whose state is determined completely. unique_ptr<T> is one of those types whose objects' moved-from state is completely determinate.

@Henri Menke 2018-07-12 01:44:27

@Yakk Okay, I'm definitely not language lawyer enough to argue about that, so I just removed this sub-sentence. I hope you agree that having moved-from objects around it is a potential source of bugs.

Related Questions

Sponsored Content

2 Answered Questions

[SOLVED] Move-only version of std::function

3 Answered Questions

[SOLVED] Is pass-by-value a reasonable default in C++11?

3 Answered Questions

2 Answered Questions

[SOLVED] Accept move-only parameter by value or rvalue reference

  • 2016-07-01 08:22:21
  • Zizheng Tai
  • 1603 View
  • 12 Score
  • 2 Answer
  • Tags:   c++ c++11

3 Answered Questions

[SOLVED] unique_ptr behaviour while passing through function

2 Answered Questions

[SOLVED] How to avoid move elision when passing a temporary by value?

0 Answered Questions

Moving a std::unique_ptr into a std::async

3 Answered Questions

[SOLVED] Should a type be move-only, just because copying may be expensive?

1 Answered Questions

[SOLVED] The move function in unique_ptr C++03 emulation

Sponsored Content