Below in the question is a simplified version of code for SO. The original code:
- Receives a structure that should not be modified or invalidated
- Creates a different structure that has some data copied from the original structure
- The newly created structure is intended to not be modifiable, all members are
const - The newly created structure cannot have a constructor that knows about the original structure
The simplified code for SO doesn't have the original structure, I just made up data with loops. However the detail which is still important is that the new structure's constructor will be passed std::vector. Those are populated in the loops and moved to the new structure
It occurred to me that the std::vector will not be needed after the new structure is made so std::move would be appropriate. I have labeled the usages as "Move 1", "Move 2", "Move 3", and "Move 4" in the code below:
#include <iostream>
#include <vector>
struct A {
const int m_a;
A() = delete;
A(const int a_a) : m_a(a_a) {}
void display() const { std::cout << " " << m_a << "\n"; }
};
struct B {
const std::vector<A> m_as;
const int m_b;
B() = delete;
B(
std::vector<A>&& a_as,
const int a_b
) :
m_as(std::move(a_as)), // Move 1
m_b(a_b)
{}
void display() const {
std::cout << " " << m_b << ":\n";
for (const A& a : m_as)
a.display();
}
};
struct C {
const std::vector<B> m_bs1;
const std::vector<B> m_bs2;
C() = delete;
C(
std::vector<B>&& a_bs1,
std::vector<B>&& a_bs2
) :
m_bs1(std::move(a_bs1)), // Move 2
m_bs2(std::move(a_bs2)) // Move 2
{}
void display() const {
std::cout << "0:\n";
for (const B& b : m_bs1)
b.display();
std::cout << "1:\n";
for (const B& b : m_bs2)
b.display();
}
};
int main() {
// Manually making up data, actual usage will take data from a different
// kind of structure and populate vectors
std::vector<B> bs1, bs2;
for (int i = 0; i < 3; ++i) {
std::vector<A> as;
for (int j = 0; j < 2; ++j)
as.emplace_back(j);
bs1.emplace_back(std::move(as), i); // Move 3
}
for (int i = 0; i < 3; ++i) {
std::vector<A> as;
for (int j = 0; j < 2; ++j)
as.emplace_back(j);
bs2.emplace_back(std::move(as), i); // Move 3
}
C c(std::move(bs1), std::move(bs2)); // Move 4
c.display();
return 0;
}
Some assumptions:
- I believe that there is no significant difference between "Move 1" and "Move 2"
- I believe that there is no significant difference between "Move 3" and "Move 4"
- To the best of my knowledge
std::forwardis not a good replacement for any of thestd::moveusages because there are no templates
The question:
Are all of the std::move usages meaningful or are any of them unnecessary?