Жёсткий БАГ 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>Таким образом, поведение вполне соответсвует стандарту.


Re[2]: Гипотеза
От: Lorenzo_LAMAS  
Дата: 02.10.06 10:24
Оценка:
Лучше почитать пропозал Стивена Адамчука, где он говорит о разрушении временных объектов.
Of course, the code must be complete enough to compile and link.
Re[3]: Гипотеза
От: remark Россия http://www.1024cores.net/
Дата: 02.10.06 11:06
Оценка: +1 :)
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Лучше почитать пропозал Стивена Адамчука, где он говорит о разрушении временных объектов.


Как только кинешь ссылочку, так сразу
А чем лучше-то? Это ж пропозал. Нам ещё как минимум несколько лет работать с существующими средствами. Баги от чтения пропозала не исчезнут


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Гипотеза
От: elcste  
Дата: 02.10.06 14:58
Оценка: 8 (1)
Здравствуйте, remark, Вы писали:

R>Как только кинешь ссылочку, так сразу


WG21/N1286
Re[3]: Гипотеза
От: remark Россия http://www.1024cores.net/
Дата: 02.10.06 15:17
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Лучше почитать пропозал Стивена Адамчука, где он говорит о разрушении временных объектов.


Не в кассу. Там о разрушении параметров.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Гипотеза
От: Lorenzo_LAMAS  
Дата: 03.10.06 09:18
Оценка:
я не очень внимательно читал твой пример, и не очень хорошо помню о чем говорил Стивен, но как раз разрушение временных объектов там хорошо и доходчиво (ИМХО) объяснялось.
Of course, the code must be complete enough to compile and link.
Re[5]: Гипотеза
От: Lorenzo_LAMAS  
Дата: 03.10.06 09:20
Оценка:
там вон даже пункт у него есть Is it a Parameter or a Temporary?
Of course, the code must be complete enough to compile and link.
Re: Жёсткий БАГ MSVC7.1 и 8 тоже
От: Кодт Россия  
Дата: 03.10.06 10:01
Оценка: 14 (2)
Здравствуйте, remark, Вы писали:

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


Написал эквивалентный код, чтобы не тащить лишнее (т.е. shared_ptr).
#include <iostream>
using std::cout;
using std::endl;

int refcount = 0;

struct share
{
    share()
    {
        ++refcount;
        cout << this << " : " << __FUNCTION__ << " : " << refcount << endl;
    }
    share(const share&)
    {
        ++refcount;
        cout << this << " : " << __FUNCTION__ << " : " << refcount << endl;
    }
    ~share()
    {
        --refcount;
        cout << this << " : " << __FUNCTION__ << " : " << refcount << endl;
    }

    int get() const
    {
        cout << this << " : " << __FUNCTION__ << " : " << refcount << endl;
        return 0;
    }
};

share make()
{
    cout << __FUNCTION__ << " : " << refcount << endl;
    return share();
}

int unfold(share tmp)
{
    cout << __FUNCTION__ << " : " << refcount << endl;
    return tmp.get();
}

void accept(int)
{
    cout << __FUNCTION__ << " : " << refcount << endl;
}


int main()
{
    cout << __FUNCTION__ << " : " << refcount << endl;
    accept(unfold(make()));
    cout << __FUNCTION__ << " : " << refcount << endl;
    return 0;
}

Проверил на VC8. Та же фигня. Причём и в релизе, и в дебаге (где, казалось бы, оптимизации отключены).
main : 0
make : 0                       -- ещё нет объектов...
0012FE84 : share::share : 1    -- вот мы его создали в make() - return share()
unfold : 1                     -- вот он уже как параметр unfold
0012FE84 : share::get : 1      -- пока что жив...
0012FE84 : share::~share : 0   -- вот мы вышли из unfold
accept : 0                     -- и к моменту входа в accept все умерли
main : 0
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[6]: Гипотеза
От: remark Россия http://www.1024cores.net/
Дата: 03.10.06 10:02
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>там вон даже пункт у него есть Is it a Parameter or a Temporary?


Я там пробежался по быстрому. Имхо ничего нового к этому вопросу пропозал не добавляет.
В разделе Is it a Parameter or a Temporary? Только ещё раз говорится, что временные объекты должны жить до точки с запятой. Это собственно я ещё в первом посте написал. Больше ничего интересного по этому вопросу я не вижу.
Он там вроде в основном говорит о том, когда должны разрушаться временные объекты, которые были созданы при инициализации параметров функции.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[7]: Гипотеза
От: elcste  
Дата: 03.10.06 11:06
Оценка: 8 (1)
Здравствуйте, remark, Вы писали:

R>Я там пробежался по быстрому. Имхо ничего нового к этому вопросу пропозал не добавляет.


Текст Адамчика отчасти объясняет причины ошибки, допущенной разработчиками MSVC, — следование 5.2.2/4

The lifetime of a parameter ends when the function in which it is defined returns.

при игнорировании 12.8/15

In such cases, the implementation treats the source and target of the omitted copy operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization.

Re[2]: Жёсткий БАГ MSVC7.1 и 8 тоже
От: night beast СССР  
Дата: 03.10.06 14:29
Оценка:
Здравствуйте, Кодт, Вы писали:

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


К>Написал эквивалентный код, чтобы не тащить лишнее (т.е. shared_ptr).


а если по ссылке передавать, то тоже не работает?
может из-за RVO гонит.
Re[3]: Жёсткий БАГ MSVC7.1 и 8 тоже
От: remark Россия http://www.1024cores.net/
Дата: 03.10.06 14:39
Оценка:
Здравствуйте, night beast, Вы писали:

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


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


К>>Написал эквивалентный код, чтобы не тащить лишнее (т.е. shared_ptr).


NB>а если по ссылке передавать, то тоже не работает?

NB>может из-за RVO гонит.

Если по ссылке, то должно работать.
здесь
Автор: remark
Дата: 02.10.06
я писал. Я так понял, что проявляется только когда "внутренняя" функция возвращает по значению, а "внешняя" принимает по значению. Т.е. компилятор совмещает эти объекты.



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

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


К>>>Написал эквивалентный код, чтобы не тащить лишнее (т.е. shared_ptr).


NB>>а если по ссылке передавать, то тоже не работает?

NB>>может из-за RVO гонит.

R>Если по ссылке, то должно работать.


так должно или работает? (нет копилятора под рукой)

R>здесь
Автор: remark
Дата: 02.10.06
я писал. Я так понял, что проявляется только когда "внутренняя" функция возвращает по значению, а "внешняя" принимает по значению. Т.е. компилятор совмещает эти объекты.


RVO
Re[4]: Жёсткий БАГ MSVC7.1 и 8 тоже
От: night beast СССР  
Дата: 04.10.06 05:56
Оценка:
R>>>>Вот минимальный код, приводящий к ошибке:

К>>>Написал эквивалентный код, чтобы не тащить лишнее (т.е. shared_ptr).


NB>>а если по ссылке передавать, то тоже не работает?

NB>>может из-за RVO гонит.

R>Если по ссылке, то должно работать.


работает.

R>здесь
Автор: remark
Дата: 02.10.06
я писал. Я так понял, что проявляется только когда "внутренняя" функция возвращает по значению, а "внешняя" принимает по значению. Т.е. компилятор совмещает эти объекты.


в мелкософт написал?
ве таки неприятный баг. вляпаешься -- фиг найдешь.

PS: гсс продолжает рулить
Re[3]: Жёсткий БАГ MSVC7.1 и 8 тоже
От: Кодт Россия  
Дата: 04.10.06 08:31
Оценка: 32 (5) :)
Здравствуйте, night beast, Вы писали:

NB>может из-за RVO гонит.


Это не RVO, а криво сделанная оптимизация копирования. Проверяем.
#include <iostream>
using namespace std;

struct Data
{
    int m_refcount;
    unsigned m_signature;
    Data() : m_refcount(0), m_signature(0x900DDA7A) { cout<<"CONSTRUCT"<<endl; }
    ~Data() { cout<<"DESTROY"<<endl; m_signature=0xDEADFACE; }
    void addref() { ++m_refcount; }
    void release() { if(--m_refcount==0) delete this; }
};
ostream& operator<<(ostream& ost, const Data& data)
{
    return ost<<"Data"<<"(ref="<<data.m_refcount<<",sig="<<hex<<data.m_signature<<dec<<")";
}

struct Ptr;
ostream& operator<<(ostream& ost, const Ptr& );

static int ids = 0;
struct Ptr
{
    int m_id; // to see lifetime of particular Ptrs
    Data* m_data;
    explicit Ptr(Data* data) : m_id(++ids), m_data(data)
    {
        m_data->addref();
        cout<<"ctor "<<*this<<endl;
    }
    Ptr(const Ptr& src) : m_id(++ids), m_data(src.m_data)
    {
        m_data->addref();
        cout<<"cctor "<<*this<<endl;
    }
    ~Ptr()
    {
        cout<<"dtor "<<*this<<endl;
        m_data->release();
    }
    
    Data* get() const
    {
        cout<<"get "<<*this<<endl;
        return m_data;
    }
};
ostream& operator<<(ostream& ost, const Ptr& ptr)
{
    return ost<<"Ptr #"<<ptr.m_id<<" ("<<*ptr.m_data<<")";
}

void accept(Data* data)
{
    cout<<"accept "<<*data<<endl;
}

Data* pass(Ptr ptr)
{
    cout<<"pass ("<<ptr<<")"<<endl;
    return ptr.get();
}

Ptr rvo_make()
{
    cout<<"rvo_make"<<endl;
    return Ptr(new Data());
}

Ptr nrvo_make()
{
    cout<<"nrvo_make"<<endl;
    Ptr ptr(new Data());
    cout<<"nrvo_make completed"<<endl;
    return ptr;
}

Ptr nonopt_make()
{
    cout<<"nonopt_make"<<endl;
    if(rand() % 2)
    {
        Ptr ptr(new Data());
        cout<<"nonopt_make completed, v1"<<endl;
        return ptr;
    }
    else
    {
        Ptr ptr(new Data());
        cout<<"nonopt_make completed, v2"<<endl;
        return ptr;
    }
}

int main()
{
    cout<<"---tmp---"<<endl;
    ids=0;
    accept(pass(Ptr(new Data())));
    
    cout<<"---rvo---"<<endl;
    ids=0;
    accept(pass(rvo_make()));
    
    cout<<"---nrvo---"<<endl;
    ids=0;
    accept(pass(nrvo_make()));
    
    cout<<"---nonopt---"<<endl;
    ids=0;
    accept(pass(nonopt_make()));
}


Получаем (VC8)
Действиеdebugrelease
TMP
CONSTRUCT
ctor Ptr #1 (Data(ref=1,sig=900dda7a))
pass (Ptr #1 (Data(ref=1,sig=900dda7a)))
get Ptr #1 (Data(ref=1,sig=900dda7a))
dtor Ptr #1 (Data(ref=1,sig=900dda7a))
DESTROY
accept Data(ref=3473816,sig=3530c0)

CONSTRUCT
ctor Ptr #1 (Data(ref=1,sig=900dda7a))
pass (Ptr #1 (Data(ref=1,sig=900dda7a)))
get Ptr #1 (Data(ref=1,sig=900dda7a))
dtor Ptr #1 (Data(ref=1,sig=900dda7a))
DESTROY
accept Data(ref=3473816,sig=3530c0)
RVO
rvo_make
CONSTRUCT
ctor Ptr #1 (Data(ref=1,sig=900dda7a))
pass (Ptr #1 (Data(ref=1,sig=900dda7a)))
get Ptr #1 (Data(ref=1,sig=900dda7a))
dtor Ptr #1 (Data(ref=1,sig=900dda7a))
DESTROY
accept Data(ref=3473816,sig=355050)

rvo_make
CONSTRUCT
ctor Ptr #1 (Data(ref=1,sig=900dda7a))
pass (Ptr #1 (Data(ref=1,sig=900dda7a)))
get Ptr #1 (Data(ref=1,sig=900dda7a))
dtor Ptr #1 (Data(ref=1,sig=900dda7a))
DESTROY
accept Data(ref=3473816,sig=355050)
NRVO
nrvo_make
CONSTRUCT
ctor Ptr #1 (Data(ref=1,sig=900dda7a))
nrvo_make completed
cctor Ptr #2 (Data(ref=2,sig=900dda7a))
dtor Ptr #1 (Data(ref=2,sig=900dda7a))
pass (Ptr #2 (Data(ref=1,sig=900dda7a)))
get Ptr #2 (Data(ref=1,sig=900dda7a))
dtor Ptr #2 (Data(ref=1,sig=900dda7a))
DESTROY
accept Data(ref=3473816,sig=355050)

nrvo_make
CONSTRUCT
ctor Ptr #1 (Data(ref=1,sig=900dda7a))
nrvo_make completed
pass (Ptr #1 (Data(ref=1,sig=900dda7a)))
get Ptr #1 (Data(ref=1,sig=900dda7a))
dtor Ptr #1 (Data(ref=1,sig=900dda7a))
DESTROY
accept Data(ref=3473816,sig=3530c0)
NonOpt
nonopt_make
CONSTRUCT
ctor Ptr #1 (Data(ref=1,sig=900dda7a))
nonopt_make completed, v1
cctor Ptr #2 (Data(ref=2,sig=900dda7a))
dtor Ptr #1 (Data(ref=2,sig=900dda7a))
pass (Ptr #2 (Data(ref=1,sig=900dda7a)))
get Ptr #2 (Data(ref=1,sig=900dda7a))
dtor Ptr #2 (Data(ref=1,sig=900dda7a))
DESTROY
accept Data(ref=3473816,sig=355050)

nonopt_make
CONSTRUCT
ctor Ptr #1 (Data(ref=1,sig=900dda7a))
nonopt_make completed, v1
cctor Ptr #2 (Data(ref=2,sig=900dda7a))
dtor Ptr #1 (Data(ref=2,sig=900dda7a))
pass (Ptr #2 (Data(ref=1,sig=900dda7a)))
get Ptr #2 (Data(ref=1,sig=900dda7a))
dtor Ptr #2 (Data(ref=1,sig=900dda7a))
DESTROY
accept Data(ref=3473816,sig=355050)
Видно, что в дебажной версии NRVO не выполняется.
Однако вне зависимости от RVO/NRVO мы получаем расстройство памяти.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[5]: Жёсткий БАГ MSVC7.1 и 8 тоже
От: Кодт Россия  
Дата: 04.10.06 09:31
Оценка: +1
Здравствуйте, night beast, Вы писали:

NB>в мелкософт написал?

NB>ве таки неприятный баг. вляпаешься -- фиг найдешь.

Причём должен рваться не только на shared_ptr, но и на CComPtr.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[6]: Жёсткий БАГ MSVC7.1 и 8 тоже
От: remark Россия http://www.1024cores.net/
Дата: 04.10.06 09:56
Оценка:
Здравствуйте, Кодт, Вы писали:

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


NB>>в мелкософт написал?

NB>>ве таки неприятный баг. вляпаешься -- фиг найдешь.

К>Причём должен рваться не только на shared_ptr, но и на CComPtr.


С любым классом, который использует разделяемое тело.
Есть пример гораздо ближе — их любимый CString



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

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


R>


К слову, вот, что Como Выводит:

main
getAAAPtr
AAA
getAAA
aaa
deleterAAA
~AAA
Re[4]: Жёсткий БАГ MSVC7.1 и 8 тоже
От: Ovl Россия  
Дата: 06.10.06 09:25
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Ptr nonopt_make()

К>{
К> cout<<"nonopt_make"<<endl;
К> if(rand() % 2)
К> {
К> Ptr ptr(new Data());
К> cout<<"nonopt_make completed, v1"<<endl;
К> return ptr;
К> }
К> else
К> {
К> Ptr ptr(new Data());
К> cout<<"nonopt_make completed, v2"<<endl;
К> return ptr;
К> }
К>}

может для полноты ощущения вместо rand() использовать volatile?
Read or Die!
Как правильно задавать вопросы
Как правильно оформить свой вопрос
Автор: anvaka
Дата: 15.05.06
Re[5]: Жёсткий БАГ MSVC7.1 и 8 тоже
От: Кодт Россия  
Дата: 06.10.06 11:04
Оценка: 1 (1)
Здравствуйте, Ovl, Вы писали:

Ovl>может для полноты ощущения вместо rand() использовать volatile?


Да без разницы — мне просто хотелось помешать компилятору.
Кстати, здесь всё равно есть возможности для NRVO, поскольку в каждой ветке ровно один объект.
А вот такой способ гарантирует невозможность NRVO
Ptr* volatile p;
Ptr nonopt_make()
{
    Ptr ptr(new Data());
    p = &ptr;
    return *p;
}
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[5]: Сообщил в мелкософт
От: remark Россия http://www.1024cores.net/
Дата: 08.10.06 10:52
Оценка: 37 (2)
Здравствуйте, night beast, Вы писали:

NB>в мелкософт написал?

NB>ве таки неприятный баг. вляпаешься -- фиг найдешь.

здесь (кстати, можете голосовать, оценивать и комментировать )

Проверил на MSVC8.0SP1 та же фигня

Если чо интересное ответят, то сообщу.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Сообщил в мелкософт
От: night beast СССР  
Дата: 08.10.06 14:12
Оценка: :)
Здравствуйте, remark, Вы писали:

R>Здравствуйте, night beast, Вы писали:


NB>>в мелкософт написал?

NB>>ве таки неприятный баг. вляпаешься -- фиг найдешь.

R>здесь (кстати, можете голосовать, оценивать и комментировать )


R>Проверил на MSVC8.0SP1 та же фигня


R>Если чо интересное ответят, то сообщу.


Что-то типа: спасибо за информацию. К сожалению не сможем починить к следующей версии
Re[7]: Сообщил в мелкософт
От: remark Россия http://www.1024cores.net/
Дата: 08.10.06 14:42
Оценка: :)
Здравствуйте, night beast, Вы писали:

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


R>>Здравствуйте, night beast, Вы писали:


NB>>>в мелкософт написал?

NB>>>ве таки неприятный баг. вляпаешься -- фиг найдешь.

R>>здесь (кстати, можете голосовать, оценивать и комментировать )


R>>Проверил на MSVC8.0SP1 та же фигня


R>>Если чо интересное ответят, то сообщу.


NB>Что-то типа: спасибо за информацию. К сожалению не сможем починить к следующей версии

NB>

Или что-то типа: Да, это известный баг. Сейчас мы можем Вам предложить только не использовать такие конструкции

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[8]: Сообщил в мелкософт
От: Vain Россия google.ru
Дата: 08.10.06 15:28
Оценка: :)
Здравствуйте, remark, Вы писали:

NB>>Что-то типа: спасибо за информацию. К сожалению не сможем починить к следующей версии

NB>>

R>Или что-то типа: Да, это известный баг. Сейчас мы можем Вам предложить только не использовать такие конструкции

R>

А может даже: boost сторонняя разработка, не мы писали — не нам и исправлять
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[9]: Сообщил в мелкософт
От: remark Россия http://www.1024cores.net/
Дата: 08.10.06 16:43
Оценка: +1
Здравствуйте, Vain, Вы писали:

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


NB>>>Что-то типа: спасибо за информацию. К сожалению не сможем починить к следующей версии

NB>>>

R>>Или что-то типа: Да, это известный баг. Сейчас мы можем Вам предложить только не использовать такие конструкции

R>>

V>А может даже: boost сторонняя разработка, не мы писали — не нам и исправлять


Хорошо, что я всё-таки упомянул так же CString и CComPtr


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Сообщил в мелкософт
От: Кодт Россия  
Дата: 09.10.06 09:02
Оценка:
Здравствуйте, remark, Вы писали:

R>здесь (кстати, можете голосовать, оценивать и комментировать )


Какая-то фигня происходит. Анонимно — вижу, не могу проголосовать. Логинюсь — не вижу.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[7]: Сообщил в мелкософт
От: remark Россия http://www.1024cores.net/
Дата: 09.10.06 09:05
Оценка:
Здравствуйте, Кодт, Вы писали:

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


R>>здесь (кстати, можете голосовать, оценивать и комментировать )


К>Какая-то фигня происходит. Анонимно — вижу, не могу проголосовать. Логинюсь — не вижу.


Может поиском попробуешь поискать, когда залогинен. Там когда хочешь новый баг зарегистрировать (жмёшь Feedback), всегда в обязательном порядке предлагается поискать похожие баги...


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Жёсткий БАГ MSVC7.1 и 8 тоже
От: Ovl Россия  
Дата: 09.10.06 09:12
Оценка:
гаранты бывают разные
вот и в vc7 не все оказывается гарантированным
Read or Die!
Как правильно задавать вопросы
Как правильно оформить свой вопрос
Автор: anvaka
Дата: 15.05.06
Re[7]: Сообщил в мелкософт
От: night beast СССР  
Дата: 09.10.06 09:13
Оценка:
Здравствуйте, Кодт, Вы писали:

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


R>>здесь (кстати, можете голосовать, оценивать и комментировать )


К>Какая-то фигня происходит. Анонимно — вижу, не могу проголосовать. Логинюсь — не вижу.


залогинься и рефрешни страницу, которую анонимно открыл.
Re[8]: Сообщил в мелкософт
От: kan Великобритания  
Дата: 09.10.06 10:07
Оценка:
night beast wrote:

> К>Какая-то фигня происходит. Анонимно — вижу, не могу проголосовать.

> К>Логинюсь — не вижу.
> залогинься и рефрешни страницу, которую анонимно открыл.

Page Not Found

The content that you requested cannot be found or you do not have permission to view it.


Т.е. анонимным юзерам можно смотреть, зарегистрированным — нельзя!
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[9]: Сообщил в мелкософт
От: night beast СССР  
Дата: 09.10.06 10:18
Оценка:
Здравствуйте, kan, Вы писали:

kan>

kan>Page Not Found

kan>The content that you requested cannot be found or you do not have permission to view it.

kan>
kan>Т.е. анонимным юзерам можно смотреть, зарегистрированным — нельзя!

а если Sign In нажать на странице с багрепортом?

в IE все работает. проверил только что.
Re[10]: Сообщил в мелкософт
От: kan Великобритания  
Дата: 09.10.06 10:32
Оценка:
night beast wrote:

> kan>Т.е. анонимным юзерам можно смотреть, зарегистрированным — нельзя!

>
> а если *Sign In* нажать на странице с багрепортом?
>
> в IE все работает. проверил только что.
По всякому пробовал... Под IE/FF, возвращался на страницу, переходил через поиск, урл правил.
Видимо, у меня логин какой-то неправильный, мне не доверяют.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[11]: Идея
От: remark Россия http://www.1024cores.net/
Дата: 09.10.06 10:36
Оценка:
Здравствуйте, kan, Вы писали:

kan>night beast wrote:


>> kan>Т.е. анонимным юзерам можно смотреть, зарегистрированным — нельзя!

>>
>> а если *Sign In* нажать на странице с багрепортом?
>>
>> в IE все работает. проверил только что.
kan>По всякому пробовал... Под IE/FF, возвращался на страницу, переходил через поиск, урл правил.
kan>Видимо, у меня логин какой-то неправильный, мне не доверяют.

Может, те кто не видят этого репорта залогинеными не участвуют в participation'е по MSVC80SP1 — я на него зарегил баг
Тогда понятно, почему система отшивает запросы — админы мелкософта наверное уже думают, на них начилась хакерская атака из России :


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Ответ
От: remark Россия http://www.1024cores.net/
Дата: 11.10.06 10:48
Оценка: 54 (1) :)
Здравствуйте, remark, Вы писали:

R>Если чо интересное ответят, то сообщу.


Comments Entered by Microsoft on 10/10/2006 at 12:09 PM
Hi: unfortunately as this bug is not specific to Visual C++ SP1 (particularly it is not a regression in behavior from Visual C++ 2005) we will not be able to fix it in this Service Pack. But we have added the bug to our list of issues for the next release of Visual C++.
Jonathan Caves
Visual C++ Compiler Team


R>


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[7]: Ответ
От: remark Россия http://www.1024cores.net/
Дата: 12.10.06 04:23
Оценка:
Здравствуйте, remark, Вы писали:

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


R>>Если чо интересное ответят, то сообщу.


R>

R>Comments Entered by Microsoft on 10/10/2006 at 12:09 PM
R>Hi: unfortunately as this bug is not specific to Visual C++ SP1 (particularly it is not a regression in behavior from Visual C++ 2005) we will not be able to fix it in this Service Pack. But we have added the bug to our list of issues for the next release of Visual C++.
R>Jonathan Caves
R>Visual C++ Compiler Team


Проверил и на msvc6.0. Я думаю, о результате Вы догадываетесь то же самое.
Т.е. баг как минимум с 98 года... а скорее всего и раньше.
Странно, неужели никто не натыкался? Jonathan Caves по крайней мере сделал вид, что он об этом не знал

R>>

R>

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[8]: Ответ
От: night beast СССР  
Дата: 12.10.06 05:07
Оценка:
Здравствуйте, remark, Вы писали:

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

R>Проверил и на msvc6.0. Я думаю, о результате Вы догадываетесь то же самое.
R>Т.е. баг как минимум с 98 года... а скорее всего и раньше.
R>Странно, неужели никто не натыкался? Jonathan Caves по крайней мере сделал вид, что он об этом не знал

Скорее всего не знал.
Другой вопрос, занимается он си++ или служит прослойкой между клиентами и программерами мелкософта
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.