Вставляя адреса в наборы, размер наборов меньше ожидаемых

Я получаю размер 1. Не должно быть 4? Я вставляю адреса целых чисел в множества.

void func(set<int*>& s1, set<int*>& s2, int a)
{
    s1.insert(&a);
    s2.insert(&a);
}

int main()
{
    set<int*> s1, s2;

    int a = 1, b = 2, c = 3, d = 4;
    func(s1, s2, a);
    func(s1, s2, b);
    func(s1, s2, c);
    func(s1, s2, d);

    cout<<"  s1.size = "<<s1.size()<<"  s2.size = "<<s2.size()<<endl;
}

Ответ 1

&a внутри func - адрес локального параметра a, а не адрес исходной переменной (a, b, c или d), который:

  • Может принимать различные значения между различными вызовами func;
  • Становится недействительным указателем, когда вы достигнете конца области, в которой объявлен a (конец func здесь).

В вашем случае, поскольку вы ничего не делаете, но вызываете func 4 раза подряд, адрес этого параметра не меняется, поэтому вы получаете размер 1 (вы вставляете один и тот же указатель 4 раза).

Это поведение определено в реализации (спасибо @Rakete1111), поскольку наборы должны будут сравнивать недопустимые указатели.

Доступ к заостренному элементу через s1 или s2 (например, **s1.begin()) есть поведение undefined.

Ответ 2

Параметр a передается по значению, это означает, что вы вставляете адрес локального параметра, скопированного из аргументов. a будет создаваться каждый раз, когда вызывается func, их адреса могут быть одинаковыми или разными; ничего не гарантировано.

И стоит отметить, что параметр a будет уничтожен при выходе из функции, после чего вставляемые указатели будут свисать.

Вы должны сделать это по-ссылке, тогда будут вставлены адреса аргументов (т.е. будут вставлены переменные a, b, c, d в main()). Эти адреса различны и не будут свисать внутри тела main().

void func(set<int*>& s1, set<int*>& s2, int& a)
{
    s1.insert(&a);
    s2.insert(&a);
}

LIVE