In the following example vec
keeps the same order before and after calling std::reverse
. If I make Foo.a
not const
and remove the copy assignment operator then the vector gets reversed properly, however I don't understand why.
When debugging the assignment operator does seem to copy the object properly when called inside std::reverse
so I don't understand what I should be doing differently.
#include <vector>
#include <algorithm>
#include <iostream>
struct Foo
{
Foo(int a, int b) : a(a), b(b) {}
Foo operator=(const Foo& other)
{
return Foo(other);
}
const int a;
int b;
Foo doThing()
{
Foo copy(*this);
copy.b ;
return copy;
}
};
void print(std::vector<Foo>& vec)
{
for (const auto& foo : vec)
{
std::cout << foo.b << '\n';
}
}
int main()
{
Foo initial(-1, 0);
std::vector<Foo> vec;
vec.push_back(initial);
for (size_t i = 0; i < 10; i )
{
vec.push_back(vec[i].doThing());
}
std::cout << "before std::reverse \n\n";
print(vec);
std::reverse(vec.begin(), vec.end());
std::cout << "\nafter std::reverse \n\n";
print(vec);
std::cout.flush();
}
CodePudding user response:
This wasn't possible prior to c 20 as const
members could not be changed via assignment w/o UB and is the reason const
members in objects were/are strongly discouraged. But now it is. But you still have to write an assignment operator. To future proof the code (past c 23) you should also include a copy ctor as the implicit copy ctor may be removed. Here's the working code and involves no UB:
#include <vector>
#include <algorithm>
#include <iostream>
#include <memory>
struct Foo
{
Foo(int a, int b) : a(a), b(b) {}
Foo& operator=(const Foo& other)
{
if (this == &other)
return *this;
std::destroy_at(this);
std::construct_at(this, other);
return *this;
}
Foo(const Foo& a) = default; // Future proof
const int a;
int b;
Foo doThing()
{
Foo copy(*this);
copy.b ;
return copy;
}
};
void print(std::vector<Foo>& vec)
{
for (const auto& foo : vec)
{
std::cout << foo.b << '\n';
}
}
int main()
{
Foo initial(-1, 0);
std::vector<Foo> vec;
vec.push_back(initial);
for (size_t i = 0; i < 10; i )
{
vec.push_back(vec[i].doThing());
}
std::cout << "before std::reverse \n\n";
print(vec);
std::reverse(vec.begin(), vec.end());
std::cout << "\nafter std::reverse \n\n";
print(vec);
std::cout.flush();
}