-1
using namespace std;

class Data {
public:
    Data() {}
    ~Data() {}

    Data(const Data& t) { cout << "Copy Constructor" << endl; }
    Data(Data&& t) noexcept { cout << "Move Constructor" << endl; }
    Data& operator=(const Data& t) {
        cout << "Copy =" << endl;
        return *this;
    }
    Data& operator=(Data&& t) noexcept {
        cout << "Move =" << endl;
        return *this;
    }
};

class Data2 : public Data {};

class Test {
public:
    void setData(std::shared_ptr<Data>&& d) { data = std::forward<std::shared_ptr<Data>>(d); }

private:
    std::shared_ptr<Data> data;
};

int main() {
    Test t;
    auto d = std::make_shared<Data>();
    t.setData(d); // error
    t.setData(move(d)); // ok

    auto d1 = std::make_shared<Data2>();
    t.setData(d1); // why ok????????????

    int debug = 0;
}

Why doesn't t.setData(d1) require std::move to convert d1 to an rvalue but t.setData(d) doesn't compile?

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
손의범
  • 19
  • 1
  • 1
    Please don't bypass the code to text ratio limits by adding repeated text, explain your problem more clearly instead – Alan Birtles Oct 09 '21 at 06:37
  • I personally think the downvotes are a tad unfair, but you _are_ approaching this in a complicated way. You may get more answers if you explain why you made `d` want temporaries instead of taking the shared pointer by value. – Ted Lyngmo Oct 09 '21 at 06:38
  • I'm sorry I didn't explain it clearly. I'll do my best next time. – 손의범 Oct 09 '21 at 09:34

1 Answers1

1

t.setData(d1) has to convert d1 to std::shared_ptr<Data>, it does this by copying into a temporary value. Temporary values are already rvalues so don't require an explicit std::move.

Note that as d1 is passed via a temporary conversion setData doesn't alter d1, you still need to use std::move for this to happen so that d1 is moved into the temporary rather than being copied. E.g in:

auto d = std::make_shared<Data>();
t.setData(std::move(d));
std::cout << d.get() << "\n";

auto d1 = std::make_shared<Data2>();
t.setData(d1);
std::cout << d1.get() << "\n";

auto d2 = std::make_shared<Data2>();
t.setData(std::move(d2));
std::cout << d2.get() << "\n";

d and d2 will end up as null pointers but d1 will still point to the object.

Note that in std::forward<std::shared_ptr<Data>>(d) as you know the exact type of d std::forward is unnecessary and you could just use std::move(d) instead.

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60