源码
#include <iostream>
#include <algorithm>
#include <set>
struct complex {
int a;
int b;
complex(int _a=0,int _b=0){
a=_a;
b=_b;
}
bool operator<(const complex& t) const {
return a<t.a;
}
bool operator==(const complex& t) const {
return a==t.a;
}
};
int main() {
std::set<complex> aa;
aa.insert(complex(114,514));
auto iter = aa.find({114,1919});
for(auto& i:aa){
std::cout<<i.a<<" "<<i.b<<std::endl;
}
std::cout<<std::endl;
std::cout<<iter->a<<" "<<iter->b<<std::endl<<std::endl;
aa.insert({1919,810}); // insert 1919,0 and 810,0 actually
for(auto& i:aa){
std::cout<<i.a<<" "<<i.b<<std::endl;
}
return 0;
}
运行的结果是:
114 514
114 514
114 514
810 0
1919 0
很明显可以看出,最后的 aa.insert({1919,810})
操作,实际上插入了两个 complex
。
最后发现问题实际上出在 initializer_list 上,如果使用 aa.insert(complex(114,514))
,这里我们使用常规方式构造了一个 complex
对象,而这一句确实没有出现问题。
但是如果直接使用 aa.insert({1919,810});
,这里 insert()
会调用 inline void std::set<complex>::insert(std::initializer_list<complex> __l)
,这个功能实际上是用于一次性插入多个值的,那么为什么编译器会优先匹配到这个重载呢?
原因
问题就出在这里,complex
的构造函数,使用了缺省值。
complex(int _a=0,int _b=0){
a=_a;
b=_b;
}
// 即使_a没有使用缺省,也一样,因为_b用了缺省
complex(int _a,int _b=0){
a=_a;
b=_b;
}
这个时候,构造一个 complex
对象,实际上甚至可以用下面的一种写法:
complex a = 114514;
这时会构造出一个 a{a=114514, b=0}
。所以实际上上文中的 aa.insert({1919,810})
相当于是 aa.insert({complex(1919,0),complex(810,0)})
,同时插入了两个对象。
如何避免
很简单……
如果使用缺省,那么请这样写:
aa.insert(complex(1919,810));
如果不使用缺省,那么原来的写法 aa.insert({1919,810})
就等同于 aa.insert(complex(1919,810))