lunawyll наткнулась на прикольное поведение c++11. Попробуйте угадать, что будет выведено, если использовать c++11?
#include <set>
#include <iostream>
using namespace std;
struct S {
int a;
int b;
S(int a = 0, int b = 0): a(a), b(b) {};
friend bool operator < (const S& first, const S& second) {
return first.a < second.a;
}
};
int main() {
set<S> s;
s.insert({2, 1});
cout << s.size();
}
Неожиданный результат, но в сет будет добавлено 2 элемента (a=2, b=0) и (a=1, b=0).
Почему это так? Дело в том, что в c++11 был добавлен еще один метод void insert (initializer_list<value_type> il);
. Получается, что {2, 1} преобразуется в initializer_list<S>
с двумя элементами (a=2, b=0) и (a=1, b=0) с помощью неявного преобразования int в S, используя конструктор, который мы описали.
GNU g++ 4.9.2 (не c++11): в сете будет один элемент (a=2, b=1).
MS VC++ 2010: ошибка компиляции.
Всем добра! :)
P.S. Каким-то образом я умудрился удалить пост, написал его заного...
UPD: О том, как я удалил пост. В английской версии сайта при редактировании поста есть кнопочка "discard" — это разве не переводится как "отмена"? Оказалось — "удалить".
Ну потому что надо explicit перед такими конструкторами писать по хорошему.
В C++11 контейнерах в подобных случаях намного полезнее писать не
s.insert({2, 1})
, аs.emplace(2, 1)
. И подобной ошибки не будет, и параметры будут perfect forward-иться.К тому же, все еще считаю, что параметры по умолчанию — зло. Хотя они и немного сокращают количество кода, но количество обидных опечаток, не заметных на этапе компиляции, значительно увеличивают.
С минимальными изменениями и чтобы работало можно написать
Но от
explicit
не спасёт.А вообще, и правда, обычно пишут
Так, конечно, делать хорошо. Но во время контеста не хочется писать лишних строк.
Минимальные изменения — это удалить конструктор и спокойно писать:
Удалить можно, но тогда не будут поля нулями инициализироваться (если это не нужно, то непонятно, зачем вообще изначально конструктор был нужен).
В данном случае он вообще не нужен, да и в том коде, в котором наткнулись на такую неприятнось, тоже был не нужен, но он был.
В с++0x можно писать:
Говоря об выстрелах в свои конечности, недавно столкнулся с забавной проблемой в поведении кода. Конкретно проблема состоит в том, что срабатывает данный ассерт :
~~~~~
~~~~~
upd. да, таки бред (\/)(*,,,*)(\/)
Ну вроде
a[i - 1]
ещё бывает равноa[i]
.Видать, какие-то два элемента равны.
Вроде как в C++98 это вообще не должно компилироваться.
Капитан в треде :)
Ну, там ближе к концу написано, что в C++98 всё работает как ожидалось. Оно вообще не должно не то что работать, а даже компилироваться — это GCC слишком добрый (хотя и выдаёт предупреждение).
Да, я неправильно написал, исправлю.