Жёсткий БАГ MSVC7.1
От: remark Россия http://www.1024cores.net/
Дата: 29.09.06 10:15
Оценка: 107 (9) -1 :)
Вот минимальный код, приводящий к ошибке:

struct AAA 
{
    AAA()
    {
        std::cout << __FUNCTION__ << std::endl;
    }

    ~AAA()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

void deleterAAA(AAA* aaa) 
{
    // Сюда попадаем раньше, чем в aaa()
    std::cout << __FUNCTION__ << std::endl;
    delete aaa;
}

typedef boost::shared_ptr<AAA> AAAPtr;

AAAPtr getAAAPtr()
{
    std::cout << __FUNCTION__ << std::endl;
    return AAAPtr(new AAA, deleterAAA);
}

AAA* getAAA(AAAPtr a)
{
    std::cout << __FUNCTION__ << std::endl;
    return a.get();
    // Здесь вызывается deleterAAA !!!  :maniac: 
}

void aaa(AAA* a) 
{
    std::cout << __FUNCTION__ << std::endl;
    // Здесь объект, на который указывает a, уже разрушен  :maniac: 
}


int main()
{
    std::cout << __FUNCTION__ << std::endl;
    // По идее здесь getAAAPtr() возвращает временный объект типа AAAPtr,
    // который должен дожить до конца вызова функции aaa(),
    // и который должен "держать" обеъкт AAA,
    // т.е. в aaa() должен попасть "живой" объект AAA
    aaa(getAAA(getAAAPtr()));
}



Вывод:

main
getAAAPtr
AAA::AAA
getAAA
deleterAAA
AAA::~AAA
aaa


Специально сверился со Священным Писанием:

12.2/3

Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created.


12.2/4

There are two contexts in which temporaries are destroyed at a different point than the end of the fullexpression.
The first context is when a default constructor is called to initialize an element of an array...


12.2/5

The second context is when a reference is bound to a temporary...


1.9/12

A full-expression is an expression that is not a subexpression of another expression. If a language construct |
is defined to produce an implicit call of a function, a use of the language construct is considered to be an |
expression for the purposes of this definition. Conversions applied to the result of an expression in order to |
satisfy the requirements of the language construct in which the expression appears are also considered to be |
part of the full-expression. [Example:
struct S { |
S(int i): I(i) { } |
int& v() { return I; } |
private: |
int I; |
}; |
S s1(1); //full-expression is call of S::S(int) |
S s2 = 2; //full-expression is call of S::S(int) |
void f() { |
if (S(3).v()) // full-expression includes lvalue-to-rvalue and |
// int to bool conversions, performed before |
// temporary is deleted at end of full-expression |
{ } |
} |
—end example]



И на что, скажите, надеяться в этой жизни???




03.10.06 14:05: Перенесено модератором из 'C/C++. Прикладные вопросы' — Кодт

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Жёсткий БАГ MSVC7.1
От: _nn_ www.nemerleweb.com
Дата: 29.09.06 11:53
Оценка:
Здравствуйте, remark, Вы писали:

R>Вот минимальный код, приводящий к ошибке:


<skip>

Может я недопонимаю.
Ваш код эквивалентнен:

typedef int AAA;
typedef boost::shared_ptr<AAA> AAAPtr;

AAAPtr f()
{
  return AAAPtr(new int)); // 5. создается объект
} // 6. Вызов конструктора копирования, объект жив. (компилятор оптимизирует его обычно)

AAA* g()
{ 
  return f().get(); // 2. вызов f
                    // 7. boost::shared_ptr<AAA>::get
  // 8. Объект умирает после вызова get, так как область видимости его ограниченна ";".
} // 9. Возврат мусора.

int main()
{
 AAA* p = g(); // 1. вызов g
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Жёсткий БАГ MSVC7.1
От: remark Россия http://www.1024cores.net/
Дата: 29.09.06 11:59
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Здравствуйте, remark, Вы писали:


R>>Вот минимальный код, приводящий к ошибке:


__><skip>


__>Может я недопонимаю.

__>Ваш код эквивалентнен:

__>
__>typedef int AAA;
__>typedef boost::shared_ptr<AAA> AAAPtr;

__>AAAPtr f()
__>{
__>  return AAAPtr(new int)); // 5. создается объект
__>} // 6. Вызов конструктора копирования, объект жив. (компилятор оптимизирует его обычно)

__>AAA* g()
__>{ 
__>  return f().get(); // 2. вызов f
__>                    // 7. boost::shared_ptr<AAA>::get
__>  // 8. Объект умирает после вызова get, так как область видимости его ограниченна ";".
__>} // 9. Возврат мусора.

__>int main()
__>{
__> AAA* p = g(); // 1. вызов g
__>}
__>



Нет. Мне надо, что бы объект был жив только в строке 2, не далее.
Т.е. тогда, когда ещё не разрушился временный объект, возвращаемый f().
Я использую голый указатель (AAA*) в той же строчке (до , где создаётся временный объект AAAPtr. В твоём примере ты используешь голый указатель не в той строчке (после , где был создан временный объект AAAPtr.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Жёсткий БАГ MSVC7.1
От: Vain Россия google.ru
Дата: 29.09.06 12:58
Оценка:
Здравствуйте, remark, Вы писали:

R>AAA* getAAA(AAAPtr& a)

R>{
R> std::cout << __FUNCTION__ << std::endl;
R> return a.get();
R> // Здесь вызывается deleterAAA !!!
R>}

R>Специально сверился со Священным Писанием:

Имхо, здесь происходит __cdecl, параметры разрушаются сразу после выхода из функции

R>И на что, скажите, надеяться в этой жизни???

На себя
R>
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: Жёсткий БАГ MSVC7.1
От: remark Россия http://www.1024cores.net/
Дата: 29.09.06 14:14
Оценка:
Здравствуйте, Vain, Вы писали:

V>Здравствуйте, remark, Вы писали:


R>>AAA* getAAA(AAAPtr& a)

R>>{
R>> std::cout << __FUNCTION__ << std::endl;
R>> return a.get();
R>> // Здесь вызывается deleterAAA !!!
R>>}

R>>Специально сверился со Священным Писанием:

V>Имхо, здесь происходит __cdecl, параметры разрушаются сразу после выхода из функции


Пусть разрушаются, но ведь ещё должен жить AAAPtr вне этой функции. Тот, из которого скопировали параметр этой функции.
А раз есть хоть один Ptr, он должен держать целевой объект.


R>>


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Жёсткий БАГ MSVC7.1
От: Константин Л. Франция  
Дата: 29.09.06 14:21
Оценка: -1
Здравствуйте, remark, Вы писали:

это не баг. Объект создается внутри функции, а не снаружи, поэтому он не обязан жить до ;
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Жёсткий БАГ MSVC7.1
От: Vain Россия google.ru
Дата: 29.09.06 17:14
Оценка:
Здравствуйте, remark, Вы писали:

R>>>Специально сверился со Священным Писанием:

V>>Имхо, здесь происходит __cdecl, параметры разрушаются сразу после выхода из функции
R>Пусть разрушаются, но ведь ещё должен жить AAAPtr вне этой функции. Тот, из которого скопировали параметр этой функции.
Ты не понял, он и живёт, это подверждает ссылка на него:
AA* getAAA(AAAPtr& a)
{

R>А раз есть хоть один Ptr, он должен держать целевой объект.
Так и происходит, но в твоём случае аргумент AAAPtr a, — это не оригинал, а копия, проинициализированная значением от getAAAPtr(). Оригинал продолжает жить, а вот копия его — умирает сразу после возврата из getAAA.

R>
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: Жёсткий БАГ MSVC7.1
От: remark Россия http://www.1024cores.net/
Дата: 30.09.06 05:50
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Здравствуйте, remark, Вы писали:


КЛ>это не баг. Объект создается внутри функции, а не снаружи, поэтому он не обязан жить до ;


А скопироваться в результат функции, по твоему, он не обязан?
Т.е. получается, что значения, возвращаемые функциями, вообще нельзя использовать, т.к. они разрушаются ещё внутри функции. Забавно.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Жёсткий БАГ MSVC7.1
От: remark Россия http://www.1024cores.net/
Дата: 30.09.06 05:55
Оценка: +2
Здравствуйте, Vain, Вы писали:

V>Здравствуйте, remark, Вы писали:


R>>>>Специально сверился со Священным Писанием:

V>>>Имхо, здесь происходит __cdecl, параметры разрушаются сразу после выхода из функции
R>>Пусть разрушаются, но ведь ещё должен жить AAAPtr вне этой функции. Тот, из которого скопировали параметр этой функции.
V>Ты не понял, он и живёт, это подверждает ссылка на него:
V>
V>AA* getAAA(AAAPtr& a)
V>{
V>

R>>А раз есть хоть один Ptr, он должен держать целевой объект.
V>Так и происходит, но в твоём случае аргумент AAAPtr a, — это не оригинал, а копия, проинициализированная значением от getAAAPtr(). Оригинал продолжает жить, а вот копия его — умирает сразу после возврата из getAAA.

Нет, это ты не понял
Копия-то пусть умирает, мне не жалко. Но при этом не должен вызываться deleterAAA().
deleterAAA() должен вызываться когда умирает последняя копия AAAPtr.
В моём примере внутри функции рушится одна копия AAAPtr внутри функции. Это всё правильно. С этим я согласен и ничего против не имею. Но при этом не должен вызываться deleterAAA(), т.к. живёт ещё первая копия AAAPtr вне функции.


R>>

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Жёсткий БАГ MSVC7.1
От: night beast СССР  
Дата: 30.09.06 06:14
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>это не баг. Объект создается внутри функции, а не снаружи, поэтому он не обязан жить до ;


что-то вы ребята не то говорите.
remark использует shared_ptr, поэтому делетер вызавается когда разрушается последний экземпляр.
по стадарту (ссылки были представлены) результат getAAAPtr() должен прожить до конца выражения.
Re[3]: Жёсткий БАГ MSVC7.1
От: Константин Л. Франция  
Дата: 30.09.06 09:41
Оценка:
Здравствуйте, remark, Вы писали:

[]

R>А скопироваться в результат функции, по твоему, он не обязан?


обязан

R>Т.е. получается, что значения, возвращаемые функциями, вообще нельзя использовать, т.к. они разрушаются ещё внутри функции. Забавно.


может быть дело в том, что объект не создавался явно в тот самом full expression? Под явно подразумевается вызов конструктора.

хотя по 12.2/3 вроде он должен дожить

R>


а что комю говорит?
Re[5]: Жёсткий БАГ MSVC7.1
От: Vain Россия google.ru
Дата: 30.09.06 11:58
Оценка:
Здравствуйте, remark, Вы писали:

R>Нет, это ты не понял

R>Копия-то пусть умирает, мне не жалко. Но при этом не должен вызываться deleterAAA().
Насчёт не должен, этого никто не сможет гарантировать, особенно на "необычных" компиляторах
В конечном итоге, всё зависит от компилятора и его версии
R>deleterAAA() должен вызываться когда умирает последняя копия AAAPtr.
Я залез в дебри Boost и в дебуге после контруирования AAAPtr a, a->pn->pi_->use_count_/weak_count_ = 1. Я так понимаю что должно быть 2?
R>В моём примере внутри функции рушится одна копия AAAPtr внутри функции. Это всё правильно. С этим я согласен и ничего против не имею. Но при этом не должен вызываться deleterAAA(), т.к. живёт ещё первая копия AAAPtr вне функции.
Я только объяснил как работает, вы лишь можете со мной не согласиться..

R>>>
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[6]: Жёсткий БАГ MSVC7.1
От: remark Россия http://www.1024cores.net/
Дата: 02.10.06 07:25
Оценка:
Здравствуйте, Vain, Вы писали:

V>Здравствуйте, remark, Вы писали:


R>>Нет, это ты не понял

R>>Копия-то пусть умирает, мне не жалко. Но при этом не должен вызываться deleterAAA().
V>Насчёт не должен, этого никто не сможет гарантировать, особенно на "необычных" компиляторах
V>В конечном итоге, всё зависит от компилятора и его версии

Я бы не стал использовать компилятор, под которым не будет работать:

f1(f2());


А тут практически такой случай... ну немного посложнее.


R>>deleterAAA() должен вызываться когда умирает последняя копия AAAPtr.

V>Я залез в дебри Boost и в дебуге после контруирования AAAPtr a, a->pn->pi_->use_count_/weak_count_ = 1. Я так понимаю что должно быть 2?
R>>В моём примере внутри функции рушится одна копия AAAPtr внутри функции. Это всё правильно. С этим я согласен и ничего против не имею. Но при этом не должен вызываться deleterAAA(), т.к. живёт ещё первая копия AAAPtr вне функции.
V>Я только объяснил как работает, вы лишь можете со мной не согласиться..

Ну да, судя по всему компилятор чего-то наоптимайзил. Убрал кое-какие-копирования. И в итоге получилась такая лажа...

R>>>>


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Гипотеза
От: remark Россия http://www.1024cores.net/
Дата: 02.10.06 07:38
Оценка: 7 (1)
Здравствуйте, remark, Вы писали:

R>Вот минимальный код, приводящий к ошибке:


R>И на что, скажите, надеяться в этой жизни???


Гипотеза, откуда растут ноги у этого бага.
Видимо компилятор заточен под оптимизацию такого кода:

f1(f2());


В таком коде не обязательно, что бы значение, возвращаемое f2() жило до конца выполнения expression.
Надо что бы оно только попало в f1(). И поэтому, видимо, компилятор конструирует значение, возвращаемое f2() сразу "в параметре" f1(). Поэтому оно и разрушается внутри f1() и не живёт до ;
Странно, что это происходит и под дебагом.
Надо так понимать, что эта ошибка будет во всех аналогичных ситуациях.
Да, точняк. Здесь тоже падает:

std::string getFilename()
{
    return "1.txt";
}

const char* extractStr(std::string s)
{
    return s.c_str();
}

int main()
{
    printf("%s", extractStr(getFilename()));
}



А если заменить
const char* extractStr(std::string s)

на
const char* extractStr(std::string& s)

или
const char* extractStr(const std::string& s)


То всё нормально.

Опасайтесь, дунайцев, временные объекты оптимизирующих...

R>


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[7]: Жёсткий БАГ MSVC7.1
От: Константин Л. Франция  
Дата: 02.10.06 08:51
Оценка:
Здравствуйте, remark, Вы писали:

[]

R>Ну да, судя по всему компилятор чего-то наоптимайзил. Убрал кое-какие-копирования. И в итоге получилась такая лажа...


скорее всего

R>>>>>

R>
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Гипотеза
От: night beast СССР  
Дата: 02.10.06 08:58
Оценка:
Здравствуйте, remark, Вы писали:

R>Да, точняк. Здесь тоже падает:


R>
R>std::string getFilename()
R>{
R>    return "1.txt";
R>}

R>const char* extractStr(std::string s)
R>{
R>    return s.c_str();
R>}

R>int main()
R>{
R>    printf("%s", extractStr(getFilename()));
R>}
R>


здесь он вроде и должен упасть
std::string'и не обязаны разделять данные.
Re: Жёсткий БАГ MSVC7.1
От: crable США  
Дата: 02.10.06 10:02
Оценка:
Насколько я понимаю, твой код должен работать вот так:

R>Вот минимальный код, приводящий к ошибке:


R>
[snip]

R>AAAPtr getAAAPtr()
R>{
R>    std::cout << __FUNCTION__ << std::endl;
R>    return AAAPtr(new AAA, deleterAAA); //a) создается временный AAAPtr, число ссылок = 1
R>} // b) при выходе, конструируется AAAPtr из временного объекта созданного в a)
// затем временный объект созданный в a) уничтожается, число ссылок = 1.

R>AAA* getAAA(AAAPtr a) //c) конструируется AAAPtr из временного объекта созданного в b)
// затем временный объект созданный в b) уничтожается, число ссылок = 1.
R>{
R>    std::cout << __FUNCTION__ << std::endl;
R>    return a.get();
R>    // Здесь вызывается deleterAAA !!!  :maniac: 
R>} // при выходе временный объект созданный в c) уничтожается, число ссылок = 0, вызывается deleterAAA

R>


[snip]

Таким образом, поведение вполне соответсвует стандарту.
The last good thing written in C was Franz Schubert's Symphony No. 9.
Re[3]: Гипотеза
От: remark Россия http://www.1024cores.net/
Дата: 02.10.06 10:10
Оценка:
Здравствуйте, night beast, Вы писали:

NB>Здравствуйте, remark, Вы писали:


R>>Да, точняк. Здесь тоже падает:


R>>
R>>std::string getFilename()
R>>{
R>>    return "1.txt";
R>>}

R>>const char* extractStr(std::string s)
R>>{
R>>    return s.c_str();
R>>}

R>>int main()
R>>{
R>>    printf("%s", extractStr(getFilename()));
R>>}
R>>


NB>здесь он вроде и должен упасть

NB>std::string'и не обязаны разделять данные.

а ну да, точно. чо-то я увлёкся.
но, тем не менее, деструктор всё равно не в кассу вызывается.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Жёсткий БАГ MSVC7.1
От: remark Россия http://www.1024cores.net/
Дата: 02.10.06 10:13
Оценка:
Здравствуйте, crable, Вы писали:

C>Насколько я понимаю, твой код должен работать вот так:


R>>Вот минимальный код, приводящий к ошибке:


R>>
C>[snip]

R>>AAAPtr getAAAPtr()
R>>{
R>>    std::cout << __FUNCTION__ << std::endl;
R>>    return AAAPtr(new AAA, deleterAAA); //a) создается временный AAAPtr, число ссылок = 1
R>>} // b) при выходе, конструируется AAAPtr из временного объекта созданного в a)
C>// затем временный объект созданный в a) уничтожается, число ссылок = 1.

R>>AAA* getAAA(AAAPtr a) //c) конструируется AAAPtr из временного объекта созданного в b)
C>// затем временный объект созданный в b) уничтожается, число ссылок = 1.
R>>{
R>>    std::cout << __FUNCTION__ << std::endl;
R>>    return a.get();
R>>    // Здесь вызывается deleterAAA !!!  :maniac: 
R>>} // при выходе временный объект созданный в c) уничтожается, число ссылок = 0, вызывается deleterAAA

R>>


C>[snip]


C>Таким образом, поведение вполне соответсвует стандарту.


А что за лишее уничтожение в точке с ?
Как бы там ни было, каждый scope должен давать одинаковое количество созданий и разрушений объектов.
А у тебя в функции getAAA() на одно создание объекта, почему-то 2 разрушения.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Жёсткий БАГ MSVC7.1
От: night beast СССР  
Дата: 02.10.06 10:18
Оценка:
Здравствуйте, crable, Вы писали:

R>>
C>[snip]

R>>AAA* getAAA(AAAPtr a) //c) конструируется AAAPtr из временного объекта созданного в b)
C>// затем временный объект созданный в b) уничтожается, число ссылок = 1.

на основаниии чего временный объект должен уничтожаться именно здесь?

R>>


C>[snip]


C>Таким образом, поведение вполне соответсвует стандарту.


Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.