C++ WTF

bleyman

Почему оно убивает временный объект на который я ссылаюсь из глобального массива (но не убивает если из локальной переменной, ни если из глобальной)?

#include <stdio.h>

struct S1
{
    const char * tag;
    S1(const char * a_tag): tag(a_tag)
    {
     printf("%s: S1\n", tag);
    }
    ~S1
    {
     printf("%s: ~S1\n", tag);
    }
    virtual void f const
    {
     printf("%s: S1::f\n", tag);
    };
};

struct S2: S1
{
    S2(const char * a_tag)
     :S1(a_tag)
    {
     printf("%s: S2\n", tag);
    }
    ~S2
    {
     printf("%s: ~S2\n", tag);
    }
    virtual void f const
    {
     printf("%s: S2::f\n", tag);
    }
};

struct Container
{
    const S1 & s;
};

const Container lst[] =
{
    {
     S2("global array"
    },
};

const S1 & global = S2("global variable");

int main
{
    // All global things are constructed before this point
    // The "global array" one is also destructed, WTF?
    printf("start\n");
    const S1 & local = S2("local variable");
    local.f; // OK
    global.f; // OK
    lst[0].s.f; // segfault
    return 0;
}

Чё за хуйня бля?
Проверил на гцц 4.6.0 и мсвц 2008.

Dasar

ссылки зло.
по идее он где-то считает, что объект создается внутри некого локального контекста, и объект прибивается, когда локальный контекст завершается

Dasar

Почему оно убивает временный объект на который я ссылаюсь из глобального массива
вот тут что-то странное написано.
C++ не проверяет же ссылочность. он просто прибивает все объекты, которые были созданы внутри данного локального контекста, вне зависимости ссылается кто-нибудь или нет

evgen5555

временный объект - закрывающая фигурная скобка - деструктор

bleyman

Хм, действительно, причём с локальным массивом та же фигня.
А нафига это сделано?
Вы же все совершенно не правы когда говорите "временный объект - закрывающая фигурная скобка - деструктор"!
Например, никогда не задумывались, почему можно писать (some_string + some_other_string).c_str ? Потому что есть специальное правило, что все темпорариз созданные внутри одного стейтмента убиваются только после выполнения этого стейтмента. А вовсе не живут до ближайшей фигурной скобки, и не до круглой тоже, между прочим!
И это типа специальная магея ссылок, что когда ты биндишь вот так к выражению, то самое внешнее темпорари (и только оно, как я понимаю) тогда живёт пока ссылка не выйдет из scope.
Почему не подпатчить правило специально для инициализаторов? Они ж даже скоуп не создают! Алсо, получается несимметрично — когда я пишу const char * s = "lol", никто у меня эту константу из-под ног не диспозит!
Очень странно и непонятно, короче.

Dasar

Почему не подпатчить правило специально для инициализаторов?
во-первых, мало кто с этим столкнулся
во-вторых, такие патчи обычно создают еще вагон других проблем

bleyman

Ну они же подпатчили правила специально для референсов, причём без каких-либо серьёзных оснований — чисто сэкономить один вызов copy constructor, который причём компилятору позволено соптимизировать нах (optimize away, забавно что это самый адекватный перевод! как я понимаю.
А тут получается асимметрия какая-то. Причём вроде бы не видно причин, почему она должна быть — ну нафига инициализаторам иметь собственный scope, там же ничего нельзя задефайнить ваще!

Dasar

ну нафига инициализаторам иметь собственный scope, там же ничего нельзя задефайнить ваще!
тогда память может утекать.
если же у тебя была бы не ссылка, то удалять-то надо

bleyman

тогда память может утекать.
если же у тебя была бы не ссылка, то удалять-то надо
Но так ссылки и так магические в этом смысле! Верхний временный объект не удаляется до конца scope! А если не ссылка, то удаляется!
Алсо, ну куда она может утекать-то, я не понимаю. Если бы initializer lists имели скоуп самой внешней инициализируемой переменной/поля, то всё было бы абсолютно ОК всё равно! Типа, инициализируешь что-то в функции — всё удалится при выходе, причём вся механика с созданием невидимых объектов и так нужна чтобы обычные ссылки инициализированные временными переменными работали. Инициализируешь что-то на уровне модуля — ну это один раз происходит же.
Кстати, можно ли писать
string & bisexual_reference = flag ? parameter : string("asdf");
?

Maurog

всем приветики в этом чате
исходный вопрос обсуждается здесь
http://stackoverflow.com/questions/5719636/lifetime-of-tempo...
http://groups.google.com/group/comp.std.c++/msg/9e779c0154d2...
еще тут почитать можно: http://rsdn.ru/forum/cpp/4257476.flat.aspx (читайте только пост Мастеркента, остальные в том числе мои посты лучше не читать, они неверные)
Крюглер и Мастеркент (Ивченков) активно пишут\фиксят новый стандарт, так что следует им доверять
вкратце: баг компиляторов
Кстати, можно ли писать
code:
string & bisexual_reference = flag ? parameter : string("asdf");
?
нельзя, ибо rvalue нельзя прибиндить к неконстантной ссылке
проще всего такой код проверять на комо

bleyman

Спасибо, я чувствовал, что что-то тут не то!
Алсо, не, я вот про какой забавный вариант спрашивал:
#include <string>
#include <stdio.h>

using std::string;

struct C
{
const char * tag;
C(const char * a_tag) : tag(a_tag)
{
printf("%s: C\n", tag);
}
~C
{
printf("%s: ~C\n", tag);
}
void f const
{
printf("%s: C::f\n", tag);
}
};

bool f(const C & ref, bool flag)
{
const C & bisexual_ref = flag ? ref : C("local");
bisexual_ref.f;
return flag;
}


int main
{
C c("main");
printf("%d\n", f(c, true;
printf("%d\n", f(c, false;
return 0;
}

Здесь получается, что компилятор вынужден (таки да!) делать довольно необычную вещь: создавать или не создавать объект с automatic storage duration в зависимости от условия. И, разумеется, уничтожать или не уничтожать.
Оставить комментарий
Имя или ник:
Комментарий: