源码
#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))
本文探讨了C++中std::set与Initializer List结合使用时出现的一个常见问题。当std::set插入含有默认构造参数的自定义类型时,可能会意外地插入多个对象。文章详细解释了问题产生的原因,并提供了简单的解决办法。
802

被折叠的 条评论
为什么被折叠?



