-1

I know ordinary std::vector::push_back() will copy the object. I hope this code would only destruct a only once, using std::move() and A(A&&) noexcept to avoid copying. But it doesn't seem to work.

Is there any way that I can construct an object before push_back() and move it into a vector perfectly?

#include <iostream>

class A {
 public:
  A() { std::cout << "construct" << this << '\n'; }
  A(A&&) noexcept { std::cout << "move" << this << "\n"; }
  A(const A&) = delete;
  ~A() { std::cout << "destruct" << this << '\n'; }
};

std::vector<A> as;
void add(A&& a) {
  std::cout << "add 1\n";
  as.push_back(std::move(a));
  std::cout << "add 2\n";
}

int main() {
  add(A());
  std::cout << "main2\n";
  return 0;
}

Output:

construct0x16d20b1fb
add 1
move0x151e068b0
add 2
destruct0x16d20b1fb
main2
destruct0x151e068b0

I hope this code would only destruct a only once, using std::move() and A(A&&) noexcept to avoid copying.

  • 4
    Even for small and simple examples, [that header file](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h) is a very bad habit. – Some programmer dude Feb 15 '23 at 13:36
  • 5
    As for your problem, the [`std::move`](https://en.cppreference.com/w/cpp/utility/move) function doesn't do what you apparently think it does. You create two objects: One in the call to `add`, and one when you push an object into your vector. Both these objects must be destructed. – Some programmer dude Feb 15 '23 at 13:38
  • 1
    When you `std::move` you are moving from an object to another object so there must be two at least. The object that you `move`d from will remain and must be destructed. – Ignacio Gaviglio Feb 15 '23 at 13:41
  • @Someprogrammerdude I'm removing it next time. – mashiro shiina Feb 15 '23 at 13:41
  • 1
    What you are describing is commonly called "destructive move". Rust supports this. C++ does not. – Drew Dormann Feb 15 '23 at 13:44
  • You can use `emplace_back` to directly construct an object in the vector – user253751 Feb 15 '23 at 13:52
  • 5
    `std::move` doesn't physically move an object - that's impossible in C++. In fact, it doesn't *do* anything at all but is just a type cast. The purpose of "moving" is to give the receiver an opportunity to take over resources from the original. That is, to move those resources rather than their owner. – molbdnilo Feb 15 '23 at 14:10

1 Answers1

1

Using Move constructor perverts copying but doesn't prevent creating new objects, you are creating an inline object with default constructor "cout : construct0x16d20b1fb" and then from that object's data your going to create a 'NEW' object and calling move constructor will transform the ownership of the object's data/resources to the new object that is being 'Constructed' so that explain the "cout : move0x151e068b0" then the line is finished so your inline object is destroyed "cout " destruct0x16d20b1fb" then your program finishes "cout : destruct0x151e068b0" your object that made via move constructor is destroyed.

you are expecting the behavior of pointers from your vector of "Objects" which is supposed to hold actual objects not pointer to other objects so it needs to containt objects and each of objects that are in that vector has a different address, unless you create your object and use a vector pointers to objects. By the way std::move is but a cast, it casts to rvalue references so when you are capturing with rvalue reference there's no need to cast it again, you should be using it like this:

A a_object1;
vector.push_back(std::move(a_object1));

and it will use the move constructor. although in this case it will cast it implicitly because you are capturing only by rvalue reference in add function unless you add an overload to this function that also takes reference there's no need.

Shahrooz
  • 196
  • 1
  • 14