为何std::reverse对含非默认拷贝赋值运算符的vector<Foo>无效?
问题根源与修复方案
核心问题分析
你的代码里std::reverse不生效,有两个关键原因:
自定义赋值运算符完全错误
你写的Foo operator=(const Foo& other)只是返回了一个临时的Foo对象,完全没有修改当前对象(this指向的实例)。赋值运算符的本质是修改左值对象的状态,而你的实现等于啥也没做——std::reverse内部依赖元素交换,交换又依赖赋值操作,结果自然是交换无效,顺序不变。const成员
a导致对象不可赋值
成员a被声明为const int,这会让编译器自动删除默认的赋值运算符(因为无法修改const成员)。就算你自定义赋值运算符,也没法修改a的值,这违反了C++对可赋值对象的要求——std::vector的元素必须是可移动/可赋值的,否则像reverse这类需要修改元素位置的算法无法正常工作。
修复步骤
步骤1:移除a的const修饰
如果要让Foo对象支持赋值操作,必须去掉a的const,因为赋值需要修改对象的成员:
int a; // 去掉const int b;
步骤2:修复或删除自定义赋值运算符
- 最简单的方式:直接删掉你写的自定义赋值运算符,让编译器生成默认赋值运算符。默认实现会自动拷贝所有非const成员,完全满足需求。
- 如果一定要自定义,必须遵循正确的签名和逻辑:
Foo& operator=(const Foo& other) { if (this != &other) { // 防止自赋值 a = other.a; b = other.b; } return *this; // 返回当前对象的引用 }
修改后的完整代码
#include <vector> #include <algorithm> #include <iostream> struct Foo { Foo(int a, int b) : a(a), b(b) {} // 删掉错误的自定义赋值运算符,用默认的即可 int a; // 移除const 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(); }
为什么之前的修改能生效?
当你把a改成非const并移除自定义赋值运算符后,编译器生成的默认赋值运算符会正确拷贝a和b的值,std::reverse内部的元素交换操作就能正常执行,自然就能反转vector的顺序了。
内容的提问来源于stack exchange,提问作者Janilson
相关产品推荐
相关产品推荐

