С++ - г.., потому что надо думать о памяти, как о ресурсе
Пиздец говно эти ваши плюсы.Ты бы хоть в теме разобрался перед наездом, а? написал про ручную работу с памятью через new/delete, так уже давно никто не делает. Или ты думаешь, что в C# нету проблем с ресурсами? Так ты напиши функцию, которая что-то читает из файла. Либо сам убедишься, либо мы тебе продемонстрируем, где у тебя утечки ресурсов на C#.
Когда же разработчику думать о содержательной части, если всё своё время он будет тратить на работу с памятью?
Так ты напиши функцию, которая что-то читает из файлаВроде бы, это должно быть что-то вроде
using(fh = File.Open(... {
Console.Write(fh.Read;
}
using(fh = File.Open(... {Ну тогда твоими же словами, если программист будет всё время думать про using, то когда ему думать про логику программы? Случай с файлом - не единичный. Иногда даже опытные C# программисты забывают написать using при работе с каким-нибудь ресурсом. Например, если ты забудешь написать using при работе с WebRequest/WebResponse, то у тебя может засориться thread pool и программа будет существенно подвисать. А вот в С++ мы не можем забыть закрыть ресурс, потому что деструкторы вызываются автоматически.
2) Ему надо думать про это только при создании, а у тебя совершенно непонятно где придётся втыкать освобождение ресурсов. Где-то создали объект - значит, надо оборачивать ручками работу с этим объектом в try...catch, ловить все исключения, если что-то поймали - освобождать память и кидать дальше; если ничего не поймали - освобождать память, в результате, код превратится в нечитаемое говно.
А вот в С++ мы не можем забыть закрыть ресурс, потому что деструкторы вызываются автоматически.В C# - тоже.
Но в c# они вызываются, когда до этих объектов дойдёт сборщик мусора; а в c++, если ты не освободил память явно - только при выходе из программы (или я ошибаюсь?)
В C# - тоже.То есть - никогда. Возможно.
Но в c# они вызываются, когда до этих объектов дойдёт сборщик мусора
Вообще, по идее, редактор должен ругаться на создание IDisposable объекта без явного определения области использования (т.е. без using). Странно, что не ругается, мне сейчас не приходит в голову, где без этого нельзя было бы обойтись.
То есть - никогдаНе позже выхода из программы.
А в C++ когда? По-моему, только при выходе из программы - то есть, даже в худшем случае тогда же, когда и в C#; а в лучшем - гораздо позже.
Кроме того, если ты создал какой-то объект, который больше нигде не хранится - то он, насколько я понимаю, будет удалён сразу, как только пропадёт из области видимости (потому что для этого не нужны сложные алгоритмы, достаточно всего лишь счётчика ссылок).
В C++ же очистка памяти от двух объектов, циклически ссылающихся друг на друга - довольно неприятное занятие.
class Class1 {
private Class2 obj = null;
public void setObj(Class2 obj) { this.obj = obj; }
}
class Class2 {
private Class1 obj = null;
public void setObj(Class1 obj) { this.obj = obj; }
}
В одном месте ты создал экземпляр класса Class1. Затем, совсем в другом месте, где-то в недрах того, что ты позвал из того метода, который создал Class1, в этот объект положили экземпляр класса Class2.
Какое количество геморроя тебе понадобится, чтобы, когда тебе не будет нужен экземпляр Class1, корректно освободить память от обоих экземпляров?
Ему не надо как-то сильно думать про using. Ему надо про это думать только тогда, когда он создаёт объект IDisposable.Ты знаешь, какое в библиотеках C# количество классов, которые реализуют IDisposable? Их дофига и больше, и каждый раз надо смотреть, что будет, если ты не напишешь using. Кстати, в некоторых случаях он необязателен. Например, Form является IDisposable, но я не видел проектов, где создание модального диалога оборочивают в using. Так что программисту на C# надо думать про using, и ещё как.
Ему надо думать про это только при создании, а у тебя совершенно непонятно где придётся втыкать освобождение ресурсов.У меня это совершенно понятно. Представь себе, RAII прекрасно работает в Си++. А про память с тобой даже говорить не о чем, ты ведь не имеешь никакого понятия про std::auto_ptr, boost::shared_ptr и boost::weak_ptr.
Но в c# они вызываются, когда до этих объектов дойдёт сборщик мусора; а в c++, если ты не освободил память явно - только при выходе из программы (или я ошибаюсь?)
В Си++ деструкторы вызываются автоматически при выходе объекта из области видимости, при его удалении. Никто из людей, с которыми я работал над Си++ проектами последние пять лет, не освобождал память (и не только память) руками. Я уже не помню, когда последний раз набирал на клавиатуре delete. Так что перед наездами надо сначала разобраться в теме. А то я уже перестал понимать, ты действительно тупой или прикалываешься тут над всеми.
В Си++ деструкторы вызываются автоматически при выходе объекта из области видимостиЧто значит "при выходе из области видимости"?
Ты, кстати, так ничего и не ответил насчёт циклических ссылок.
при его удаленииКаком удалении? Для меня "при удалении" означает "при ручном удалении".
boost::someshitАга, костыли
Не позже выхода из программы.Да какая разница, что не позже выхода, если клиент открывает 10 окон, они подряд обращаются к БД и начиная с пятого окна не могут завершить асинхронную операцию, потому что маленький thread pool запросов забит незакрытыми соединениями? И не просрутся эти пять окон до тех пор, пока не сработает GC, и все будут думать, что же это за хитрый баг.
? По-моему, только при выходе из программы - то есть, даже в худшем случае тогда же, когда и в C#; а в лучшем - гораздо позже.
В Си++ ровно тогда, когда будет автоматически вызван деструктор. Представь себе, умные дяди додумались даже до того, чтобы вызывать деструкторы при исключениях. Таким образом, ловить исключения мне надо только там, где обрабатывается ошибка.
Какое количество геморроя тебе понадобится, чтобы, когда тебе не будет нужен экземпляр Class1, корректно освободить память от обоих экземпляров?
Одна из спорных тем, но я не считаю её проблемной для Си++. Потому что мне из всего геморроя понадобится только boost::weak_ptr.
Представь себе, умные дяди додумались даже до того, чтобы вызывать деструкторы при исключенияхИ как же эти "умные дяди" определяют, какие именно объекты надо уничтожать?
Или твои умные дяди - маги?
Или твои умные дяди на каждом исключении вызывают сборщик мусора, несуществующий в чистых плюсах?
Да какая разница, что не позже выхода, если клиент открывает 10 окон, они подряд обращаются к БД и начиная с пятого окна не могут завершить асинхронную операцию, потому что маленький thread pool запросов забит незакрытыми соединениями?Как меня научил много лет назад, именно для этого умные люди и придумали IDisposable; и подобные классы должны его имплементить, а работать с этими окнами ты должен через using. Именно потому, что деструктор будет вызван хз когда (и тут тебе язык уже не поможет; наоборот, языки со сборщиками мусора вызывают деструкторы раньше, чем без сборщиков).
Одна из спорных тем, но я не считаю её проблемнойЯ бы кинул в тебя картинкой, да не найду её...
Ты можешь не считать это проблемой, но на самом деле - это огромная проблема, это самая большая проблема при автоматической чистке памяти.
Что значит "при выходе из области видимости"?Когда вызываются деструкторы в Си++ ты можешь прочитать в википедии. А гугл наверняка знает, что значит выход из области видимости.
Каком удалении? Для меня "при удалении" означает "при ручном удалении".Тогда что для тебя значит "ручное удаление"? Ты хоть понимаешь, что можно сказать, что using и деструкторы функционально эквивалентны (разве что деструкторы более универсальны)? Я могу написать программу без единого слова delete и там не будут утекать ни память, ни ресурсы.
Ага, костыли
Костыли у тебя в голове держат твою единственную прямую извилину. boost::smart_ptr входит в новый стандарт Си++, причём почти что с момента появления.
И как же эти "умные дяди" определяют, какие именно объекты надо уничтожать?Они просто думают головой, а не жопой. Каким образом в Си++ вызываются деструкторы при выбрасывании исключений и к каким проблемам это приводит знают и гугл, и википедия.
Как меня научил много лет назад, именно для этого умные люди и придумали IDisposable; и подобные классы должны его имплементить, а работать с этими окнами ты должен через using. Именно потому, что деструктор будет вызван хз когда (и тут тебе язык уже не поможет; наоборот, языки со сборщиками мусора вызывают деструкторы раньше, чем без сборщиков).Этот пример был о том, что будет, если кто-то забудет про using. Что случается. А вот про деструктор Си++ программист забыть не может, потому что он вызывается автоматически. И, к сведению, гугл знает, что языки со сборщиками мусора вообще не гарантируют вызов файналайзера. А ты этого не знаешь, но лезешь спорить.
Я бы кинул в тебя картинкой, да не найду её...
Ты можешь не считать это проблемой, но на самом деле - это огромная проблема, это самая большая проблема при автоматической чистке памяти.
Не надо кидать в меня картинкой. Ты мне ещё предложи поработать у вас на "самой удобной в мире панели". Я использую boost::weak_ptr и у меня нет никаких проблем.
Когда вызываются деструкторы в Си++ ты можешь прочитать в википедииСсылку.
А гугл наверняка знает, что значит выход из области видимостиКлючевые слова.
Тогда что для тебя значит "ручное удаление"?Ручной вызов delete.
Ты хоть понимаешь, что можно сказать, что using и деструкторы функционально эквивалентныАга, и вообще, любая программа на высокоуровневом языке функционально эквивалентна откомпилированной программе. Давай, пиши свой высокоуровневый проект на ассемблере.
Никакой же эквивалентности для разработчика тут нет.
Одно дело - написать блок using и операции с ресурсом осуществлять внутри этого блока - всё будет замеательно видно, где нужно, будут правильные отступы итд; а в конце будет всего лишь одна закрывающая фигурная скобка.
А другое дело - написать совершенно незаметный среди прочего кода new, а потом ещё в десяти местах расставить такой же незаметный delete, и потом искать, где ресурс освобождается.
Ты ещё предложи
if(...) {
doSomething;
} else {
doSomethingOther;
}
заменить на
if(...);
doSomething;
else;
doSomethingOther;
endif;
А что, функционально ведь то же самое!
boost::smart_ptr входит в новый стандарт Си++,Новый стандарт Си++, теперь и с вашими любимыми костылями!
Каким образом в Си++ вызываются деструкторы при выбрасывании исключений и к каким проблемам это приводит знают и гугл, и википедия.Ещё скажи "знает интернет".
Ссылки в студию.
Этот пример был о том, что будет, если кто-то забудет про using. Что случаетсяЭто значит, что забывший - неудачник. В плюсах ему будет не легче.
А вот про деструктор Си++ программист забыть не может, потому что он вызывается автоматически.Ага - автоматически при выходе из программы.
панелиЧто тебе не понравилось в этом слове?
Каким образом в Си++ вызываются деструкторы при выбрасывании исключений и к каким проблемам это приводит знают и гугл, и википедия.Ты же меня тут убеждаешь, что никаких проблем нет, и что в плюсах вообще думать об освобождении ресурсов не надо, всё автоматически будет заебись
Ссылку.Вот ещё, сам найдёшь, если захочешь поумнеть. Здесь один ты не знаешь элементарных вещей.
Ключевые слова.
Ладно, так и быть, помогу инвалиду. Ключевые слова: С++ область видимости
Ручной вызов delete.Ты хоть читаешь, о чём тебе пишут-то? Современные прикладные программы на Си++ пишут без delete. Посмотри дальше своего носа хоть один раз.
Одно дело - написать блок using и операции с ресурсом осуществлять внутри этого блока - всё будет замеательно видно, где нужно, будут правильные отступы итд; а в конце будет всего лишь одна закрывающая фигурная скобка.Ты вообще слушаешь, о чём тебе говорят? Какой delete? Забудь про delete.
А другое дело - написать совершенно незаметный среди прочего кода new, а потом ещё в десяти местах расставить такой же незаметный delete, и потом искать, где ресурс освобождается.
Новый стандарт Си++, теперь и с вашими любимыми костылями!
Если называть костылями стандартную библиотеку, то про .NET тебе лучше помолчать. А то иначе, как креслом-каталкой, библиотеку для поддержки C# назвать не сможешь.
Зачем ты споришь?
Новый стандарт Си++, теперь и с вашими любимыми костылями!
Не только пишет на C++ и не только он прекрасно живет и не пишет delete в своем коде. И не ловит утечек. Наверное так делают большинство программистов на С++. Прямая работа с памятью обычно в универе, в компаниях все работа с памятью скрыта. Команду delete в коде встретить почти не реально, у многих и команд new почти нет. Вся работа с памятью давно обернута в конструкторы и деструкторы. И никто не ищет, куда что пропало. При этом мы вообще без boost обходимся и тоже никаких проблем не испытываем. Я бы даже добавил, что то, как ведет себя занятая память в приложениях на С++ гораздо стабильнее, чем на языках со сборщиками мусора. Если у нас есть требования на программу, что она не может ни в какой момент времени занимать больше 120Мб - то на С++ мы этого можем добиться. А вот как ты будешь контроливровать сборщики мусора - я вообще с трудом понимаю. Тем более в момент сборки почему-то обычно еще и процессор занят немного не тем, что хотят от нашей программы. Заказчикам часто интересно не среднее время работы, а максимальное, и когда в какой-то момент начнется долгая сборка, занимающая часть процессороного времени, можно легко вылететь за ограничения на время.
А вот про деструктор Си++ программист забыть не может, потому что он вызывается автоматически.Пенартур - ты уебан. Вот тебе программа, кури, пока не поймёшь, почему "2" напечатается перед "1". Выход из программы-то после печати "1".
--------------------------------------------------------------------------------
Ага - автоматически при выходе из программы.
#include <iostream>
class C
{
public:
~C
{
std::cout << "2" << std::endl;
}
};
int main(int, char*[])
{
{
C c;
}
std::cout << "1" << std::endl;
return 0;
}
Ты же меня тут убеждаешь, что никаких проблем нет, и что в плюсах вообще думать об освобождении ресурсов не надо, всё автоматически будет заебисьО каких проблемах я говорил ты сможешь найти в гугле. Форум и пользователи "лучшей в мире панели" в тебя верят.
Вот ещё, сам найдёшь"Ты неправ, и это можно подтвердить - про то, что твои утверждения неверны, якобы знают и гугл, и википедия! Но ключевые слова для поиска я тебе не скажу, потому что не знаю. Захочешь, сам найдёшь"
С++ область видимостиСпасибо, всё стало понятно, не видит дальше своего носа, и считает, что, если переменная определена, например, в каком-нибудь методе - то после выхода из этого метода она нигде не используется.
Если называть костылями стандартную библиотекуЭто смотря с какой стороны посмотреть.
Был дико убогий C++. А потом к дико убогому C++ придумали убогие костыли, чтобы хоть как-то компенсировать убогость C++. После того, как появились эти костыли (лет через 20 после появления самого С++ кто-то решил их включтиь в новый стандарт С++, чтобы всё смотрелось не так убого.
От этого костыли костылями быть не перестают.
то про .NET тебе лучше помолчатьНе угадал.
Вот если бы C# двадцать лет существовал без BCL и дженериков, как и других жизненно необходимых вещей, а потом в Новом Стандарте ТМ их бы прикрутили в виде костылей - они были бы костылями.
Тот же вопрос к тебе - что делать с циклическими ссылками?
Вот тебе программа, кури, пока не поймёшь, почему "2" напечатается перед "1".А теперь скажи мне, что будет, если C положится куда-то ещё.
Что будет с циклическими ссылками - они ведь, поди, удалятся только после выхода из программы
Или до него - и тогда у нас всё побъётся из-за неверных ссылок.
Или до него и с умом - и тогда у нас всё будет тормозить, потому что выйдет тот же самый сборщик мусора, только в форме костыля.
ЗЫ: Я так и не понял, какого хуя ты приебался к слову "панель"? Больше сказать нечего?
Спасибо, всё стало понятно, не видит дальше своего носа, и считает, что, если переменная определена, например, в каком-нибудь методе - то после выхода из этого метода она нигде не используется.О, пенартур ещё не знает разницу между ссылочными и структурными типами. Хотя что он, собственно говоря, знает? Ты программу посмотрел, понял, где и как вызываются деструкторы?
Тот же вопрос к тебе - что делать с циклическими ссылками?Тебе на этот вопрос уже ответили. В Си++ для этого используют boost::weak_ptr. Это же является ключевым словом для поиска в гугле.
О каких проблемах я говорил ты сможешь найти в гугле.Знаешь что, ? Ты идиот, еблан, и совершенно полностью неправ, потому что нихуя не понимаешь.
Подтверждение этого можешь найти в гугле. Сам догадайся, что там искать.
Ты программу посмотрел, понял, где и как вызываются деструкторы?Такое ощущение, что они вызываются тогда, когда количество ссылок на объект становится равным нулю.
Соответственно, в программах, чуть более сложных твоего примера, такая "чистка памяти" ничего полезного не делает. Может быть, тебе удастся сэкономить несколько процентов, и у тебя с такой "чисткой" памяти будет утекать не десять метров в минуту, а всего-навсего девять с половиной.
Например, Form является IDisposable, но я не видел проектов, где создание модального диалога оборочивают в using.
гыыы, лол Видимо, ты не видел нормальных проектов на C# . Если у Form не вызывать Dispose, то идет утечка девкрипторов, а они, действительно, кончаются, это несложно воспроизвести.
А теперь скажи мне, что будет, если C положится куда-то ещё.Для него, представь себе, вызовется конструктор копирования! Переходим ко второму упражнению, что выдаст на экран эта программа? Подсказка: выдаёт 2, 2, 1. И опять 1 после 2, как же так?
#include <iostream>
class C
{
public:
~C
{
std::cout << "2" << std::endl;
}
};
C f
{
C c;
return c;
}
int main(int, char*[])
{
f;
std::cout << "1" << std::endl;
return 0;
}
Что будет с циклическими ссылками - они ведь, поди, удалятся только после выхода из программы
Боюсь, что уровень твоего интеллекта не позволяет тебе пока что понять, что к чему у нас с кольцевыми указателями. Как только пройдём азы, я тебе покажу, что будет с кольцевыми указателями и как правильно на Си++ сделать агрегацию подобную той, что ты написал выше.
ЗЫ: Я так и не понял, какого хуя ты приебался к слову "панель"? Больше сказать нечего?
В гугл, жЫвотное. Хотя ладно, ты ведь туда не ходишь... http://musicmp3.spb.ru/info/256131/malenjkaya_devochka_s_paneli.htm
Вообще, по идее, редактор должен ругаться на создание IDisposable объекта без явного определения области использования (т.е. без using).Стандартный враппер класса, реализующего IDisposable, создает объект в конструкторе, и сам реализует IDisposable, и вызывает Dispose объекта в своем методе Dispose.
Такое ощущение, что они вызываются тогда, когда количество ссылок на объект становится равным нулю.Третий урок азов Си++: в этом языке нету подсчёта ссылок.
Соответственно, в программах, чуть более сложных твоего примера, такая "чистка памяти" ничего полезного не делает. Может быть, тебе удастся сэкономить несколько процентов, и у тебя с такой "чисткой" памяти будет утекать не десять метров в минуту, а всего-навсего девять с половиной.
Видимо, ты не видел нормальных проектов на C# . Если у Form не вызывать Dispose, то идет утечка девкрипторов, а они, действительно, кончаются, это несложно воспроизвести.Я знаю, к чему это приводит. Я сам участвовал в нормальных проектах, не гони тут. И при этом я ни разу не встречал ни кода с using(Form ни проблем с дескрипторами. Видимо, окна у винды заканчиваются намного позже отработок GC.
Знаешь что, ? Ты идиот, еблан, и совершенно полностью неправ, потому что нихуя не понимаешь.penartoor'чег, у тебя проблема в том, что ты лезешь спорить, ничего не зная по теме. Основываясь на том, что кто-то где-то говорит, что в Си++ нет GC, ты лезешь с утверждениями о том, что все должны освобождать память руками. При этом ты совершенно не знаешь, как функционирует этот язык.
Подтверждение этого можешь найти в гугле. Сам догадайся, что там искать.
Видимо, окна у винды заканчиваются намного позже отработок GC.У нас в проекте было место, в котором мы поленились (точнее поставили туду и отложили) корректно вызывать диспоуз у форм. Я сам реально наблюдал, что дескрипторы заканчиваются, когда подолгу (но не сильно долго) работал с нашей прогой. А наши замечательные индусские тесторы выявили этот баг при первом же тестировании .
Для него, представь себе, вызовется конструктор копирования!Похоже, я не очень хорошо (для адептов плюсов) выразился. Если я ещё куда-то передам ссылку на этот объект (копировать всё целиком при каждом чихе - тут сразу память кончится, и никакая чистка тебя не спасёт; да и времени на это копирование у тебя дофига уходить будет).
Переходим ко второму упражнению, что выдаст на экран эта программа? Подсказка: выдаёт 2, 2, 1.Успокойся, я уже понял, что ты всегда всё будешь копировать.
Ты тут распинался по поводу объектов окон, подключений итп - их ты тоже копировать собираешься?
А сколько времени твоя программа тратит на копирование, относительно общего времени её выполнения?
У нас в проекте было место, в котором мы поленились (точнее поставили туду и отложили) корректно вызывать диспоуз у форм. Я сам реально наблюдал, что дескрипторы заканчиваются, когда подолгу (но не сильно долго) работал с нашей прогой. А наши замечательные индусские тесторы выявили этот баг при первом же тестировании .Забавно, как же вы сделали более десятка тысяч окон? Мы стали диспозить вьюхи в проекте на WPF. Кстати, там дескрипторы могут заканчиваться гораздо быстрее, всё-таки они иногда представлют собой directx ресурсы.
Стандартный враппер класса, реализующего IDisposable, создает объект в конструкторе, и сам реализует IDisposable, и вызывает Dispose объекта в своем методе Dispose.Не понял
Третий урок азов Си++: в этом языке нету подсчёта ссылок.Ага, там ссылки просто бьются
Забавно, как же вы сделали более десятка тысяч окон?на одно окно расходуется не один дескриптор, и количество окон не заходило за несколько сотен. У нас проблема была кажется с Panel.
Похоже, я не очень хорошо (для адептов плюсов) выразился. Если я ещё куда-то передам ссылку на этот объект (копировать всё целиком при каждом чихе - тут сразу память кончится, и никакая чистка тебя не спасёт; да и времени на это копирование у тебя дофига уходить будет).Ты опять плохо выразился. Ссылки у нас работают без проблем, без копирования. Куда тебе нужно передать ссылку/указатель/значение объекта? Куда бы ты не передавал, деструкторы всё равно будут вызываться при выходе переменных из области видимости или при удалении объекта, независимо от выбрасывания исключений. (Педантичным читателям напомню, что я знаю о выбрасывании из деструктора.) Писать руками delete при этом не нужно. Память не утечёт.
Ага, там ссылки просто бьютсяНет, их там просто нет. Я же говорю, прежде чем спорить, тебе следует понять хотя бы базовые вещи о предмете спора.
Куда тебе нужно передать ссылку/указатель/значение объекта?Я тебе показал примитивный пример - два объекта хранят внутри себя ссылки друг на друга.
Создали один объект, передали его какой-то функции, она создала второй объект с ссылкой на первый, сообщила первому объекту о втором - получили циклические ссылки.
Вышли из функции - и что, удалять второй объект? А ничего, что первый хранит на него ссылку и мб потом будет где-то использовать?
Вышли из того блока, где определили первый объект - а его удалять нельзя, на него точно так же ссылается другой объект.
В результате, уже ни один из этих двух объектов не нужен, а в памяти они хранятся.
Стандартный враппер класса, реализующего IDisposable, создает объект в конструкторе, и сам реализует IDisposable, и вызывает Dispose объекта в своем методе Dispose.
Не понял
public class StreamWriterWrapper: IDisposable
{
private readonly StreamWriter streamWriter;
public StreamWriterWrapper
{
this.streamWriter = new StreamWriter;
}
public void Dispose
{
streamWriter.Dispose;
}
}
Я же говорю, прежде чем спорить, тебе следует понять хотя бы базовые вещи о предмете спора.Похоже, что всё-таки тебе стоит понять, что у слов есть и не то значение, которое ты зазубрил вместе с плюсами.
Если тебе надо положить один объект в другой и в третий, то во втором и третьем объектах будут храниться либо новые объекты, копии первого; либо ссылки на первый (или сам этот первый объект - это одно и то же, вопрос терминологии).
Как же у вас может "просто не быть" ссылок? Вы всё-таки по каждому чиху бросаетесь всё копировать?
Или ты про сложности для редактора в таком случае? (Создали StreamWriter просто так, а using написали от StreamWriterWrapper(StreamWriter? Да, непонятно, что с таким хреновым с этой точки зрения кодом делать, об этом я не подумал
StreamWriterWrapper(StreamWriter?извини, я сначала не тот кусок кода написал, сейчас поправил. Объект StreamWriter снаруже вообще никак не виден.
объект StreamWriter просто нужен для внутренней работы класса.
Я тебе показал примитивный пример - два объекта хранят внутри себя ссылки друг на друга.
Создали один объект, передали его какой-то функции, она создала второй объект с ссылкой на первый, сообщила первому объекту о втором - получили циклические ссылки.
Вышли из функции - и что, удалять второй объект? А ничего, что первый хранит на него ссылку и мб потом будет где-то использовать?
Вышли из того блока, где определили первый объект - а его удалять нельзя, на него точно так же ссылается другой объект.
В результате, уже ни один из этих двух объектов не нужен, а в памяти они хранятся.
Прочитай хоть одну книжку по С++ ). Ну или по С. Удаление объекта происходит не тогда, когда на него нет ссылок ). Твои циклические ссылки с освобождением памяти в С++ никак не связаны.
Бесплатный цирк Ты вообще хоть раз на плюсах писал, или с теоретических позиций споришь?
1) IDisposable объект создаётся внутри using
, либо:
2) IDisposable объект создаётся внутри динамического метода класса, имплементящего IDisposable; хранится внутри экземпляра этого класса (в this); и явно dispose-ится в dispose. Правда, плохо получается, если его могут создать несколько раз; но это уже похоже на злонамеренный обход проверки, и на это можно забить. А от опечаток поможет.
Я тебе показал примитивный пример - два объекта хранят внутри себя ссылки друг на друга.Так ты понял или нет, что delete нам не нужен? (Оставим пока что вопрос про кольцевые указатели.)
Прочитай хоть одну книжку по С++Читал.
Удаление объекта происходит не тогда, когда на него нет ссылок ). Твои циклические ссылки с освобождением памяти в С++ никак не связаныЯ тут уже пару часов пытаюсь получить от кого-нибудь информацию, что произойдёт в случае с циклическими ссылками - ссылки станут указывать в никуда или объекты не удалятся.
Вы мне в разных, независимых постах отдельно говорите, что не произойдёт первого и не произойдёт второго. А что произойдёт?
Я вот не вижу, как могут и ссылки не испортиться, и объекты удалиться.
И прежде, чем что-то писать, стоит прочитать не только конкретный пост, на который отвечаешь, выдранный из контекста, но и всю нить обсуждения. А то получается спор вида XXX: "Очевидно, произойдёт либо А, либо Б. Похоже, что в данном случае произойдёт А"; YYY: "Нифига, А не произойдёт, ты ничего не понимаешь, читай книжки"; XXX: "Понятно, значит произойдёт Б"; ZZZ: "Б не может произойти, прочитай хотя бы одну книжку, прежде чем писать такой бред"; XXX: "То есть, всё-таки произойдёт А?"; YYY: "Ты что, не слушал? А произойти не может!"
Вы спорите с тем, на чём я и не настаиваю; но так и не отвечаете на мой вопрос.
Так ты понял или нет, что delete нам не нужен? (Оставим пока что вопрос про кольцевые указатели.)Вообще-то, в кольцевых указателях и заключается всё самое интересное.
Ты вообще хоть раз на плюсах писалПредставляешь, писал. Плюсы показали себя полным говном.
Кстати, PHP - так себе, а вот на C# писать - одно удовольствие.
Похоже, что всё-таки тебе стоит понять, что у слов есть и не то значение, которое ты зазубрил вместе с плюсами.Представь себе, я прекрасно знаю как Си++, так и Java, и C#. И ещё до кучи языков типа Lua и подобных.
Если тебе надо положить один объект в другой и в третий, то во втором и третьем объектах будут храниться либо новые объекты, копии первого; либо ссылки на первый (или сам этот первый объект - это одно и то же, вопрос терминологии).У нас нету ссылочных типов, но у нас есть ссылки и указатели. Чтобы спорить, надо знать предмет спора. Нет, мы не копируем, и не используем delete. Мы используем boost::smart_ptr, хотя уже можно написать std:: tr1 ::shared_ptr
Как же у вас может "просто не быть" ссылок? Вы всё-таки по каждому чиху бросаетесь всё копировать?
Кстати, вот тебе пример кода уже на C#, просто чтобы объяснить тебе, что бывают ссылочные и не ссылочные типы.
class Program
{
struct S
{
public int i;
}
class C
{
public int i = 0;
}
static void useClass(C c)
{
c.i = 15;
}
static void useStruct(S s)
{
s.i = 15;
}
static void Main(string[] args)
{
C c = new C;
useClass(c);
S s = new S;
useStruct(s);
Console.WriteLine("c.i=" + c.i + ", s.i=" + s.i);
}
}
Я тут уже пару часов пытаюсь получить от кого-нибудь информацию, что произойдёт в случае с циклическими ссылками - ссылки станут указывать в никуда или объекты не удалятся.Вы мне в разных, независимых постах отдельно говорите, что не произойдёт первого и не произойдёт второго. А что произойдёт?Я вот не вижу, как могут и ссылки не испортиться, и объекты удалиться.И прежде, чем что-то писать, стоит прочитать не только конкретный пост, на который отвечаешь, выдранный из контекста, но и всю нить обсуждения. А то получается спор вида XXX: "Очевидно, произойдёт либо А, либо Б. Похоже, что в данном случае произойдёт А"; YYY: "Нифига, А не произойдёт, ты ничего не понимаешь, читай книжки"; XXX: "Понятно, значит произойдёт Б"; ZZZ: "Б не может произойти, прочитай хотя бы одну книжку, прежде чем писать такой бред"; XXX: "То есть, всё-таки произойдёт А?"; YYY: "Ты что, не слушал? А произойти не может!"Вы спорите с тем, на чём я и не настаиваю; но так и не отвечаете на мой вопрос.C++ обладаешь чудесным свойством. Когда программист хочет, чтобы объекты, ссылающиеся друг на друга удалялись сразу - они удаляются сразу. Когда хочет, чтобы они удалялись, когда не осталось внешних ссылок на них, кроме тех, которыми они друг на друга ссылаются, - они ведут себя именно так. А когда хотят, чтобы они удалялись только при завершении процесса, то они удаляются при завершении процесса. Для того, тобы компилятор угадал, что хочет пользователь, придумали специальные волшебные классы-обёртки, автоприведение типов при вызове функций и переопределение оператора ->. А ты эти волшебные вещи называешь граблями.
Вообще-то, в кольцевых указателях и заключается всё самое интересное.Мы о них обязательно поговорим, когда ты скажешь, понял ты, delete писать не нужно или не понял?
Кстати, вот тебе пример кода уже на C#, просто чтобы объяснить тебе, что бывают ссылочные и не ссылочные типы.Я в курсе, что структуры всегда копируются. На то они и структуры.
Ещё, кстати, у структур не бывает конструкторов и деструкторов - странно, правда?
Мы используем boost::smart_ptr, хотя уже можно написать std:: tr1 ::shared_ptrА на "старом" чистом C++ без всех этих костылей?
Я понял что тебе не нравится. Но я плохо понимаю твой пример. Точнее, мне кажется, я плохо понимаю твой пример, который для тебя очевиден, по той причине, что ты почти не писал на С++. Что у тебя за объекты? Они лежат в памяти или на стеке? Если в памяти, то мы их держим за смартпоинтеры? Если они ссылаются друг на друга просто, но мы их просто удалим, когда они перестанут быть нам нужны. От наличие в них ссылок друг на друга нам ни жакро, ни холодно. Или у них как раз друг на друга хранятся смартпоинтеры? Тогда в этом случае да, появится рекурсивная зависимость (если во всех промежуточных вопросах стоит правильный ответ но вот я только не понимаю, на фига я бы так стал делать. То есть обычные циклические ссылки - это вообще не проблема. Но если хотеть именно сделать такую зависимость как ты, то да, будет плохо. Но она нужна только для того, чтобы как раз плохо и сделать (ты же не ругаешься, что если 0 / 0 то тебе почему-то не дают 1 в ответе). В таких ситуациях проще просто сделать есть объект, за которым мы следим (и когда он нам больше не нужен - он сам пропадет а он в свою очередь, когда будет уничтожаться, заодно подчистит всю ту память, что тебе была нужна для игр с твоими перекрекстными и циклическими ссылками.
Я тут уже пару часов пытаюсь получить от кого-нибудь информацию, что произойдёт в случае с циклическими ссылками - ссылки станут указывать в никуда или объекты не удалятся.
Вы мне в разных, независимых постах отдельно говорите, что не произойдёт первого и не произойдёт второго. А что произойдёт?
Я вот не вижу, как могут и ссылки не испортиться, и объекты удалиться.
Кстати, если верить википедии, все эти твои boost-ы нифига не включены в стандарт C++, хоть нынешний, хоть будущий. Да, они есть в C++0x, но тут речь идёт о C++, а не о других языках.
Вышли из функции - и что, удалять второй объект? А ничего, что первый хранит на него ссылку и мб потом будет где-то использовать?А вот не надо так писать. Ссылки стоит заменить на указатели и возложить на один из объектов заботу об удалении другого. В Qt именно так и сделано с виджетами.
А то, что в C++ можно отстрелить себе ногу, все и так знают.
Кстати, если верить википедии, все эти твои boost-ы нифига не включены в стандарт C++, хоть нынешний, хоть будущий. Да, они есть в C++0x, но тут речь идёт о C++, а не о других языках.Если бы ты удосужился прочитать ещё пару предложений, то ты бы понял, что C++0x - это название стандарта для C++, а TR1 - расширение стандартной библиотеки.
Вот если бы C# двадцать лет существовал без BCL и дженериков, как и других жизненно необходимых вещей, а потом в Новом Стандарте ТМ их бы прикрутили в виде костылей - они были бы костылями.Кстати, это что, означает, что C# 3.0, LIINQ и WPF ты считаешь костылями C#?
Ссылки стоит заменить на указатели и возложить на один из объектов заботу об удалении другого. В Qt именно так и сделано с виджетами.Понимаешь, он считает, что для этого придётся написать delete руками. Но для того, чтобы ему что-то втолковать, он сначала должен понять, что Си++ сам не считает ссылки, что Си++ автоматически вызывает деструкторы, и так далее. Тогда ему можно будет показать boost::weak_ptr
А на "старом" чистом C++ без всех этих костылей?А ничего, что boost написан на старом чистом C++?
Они лежат в памяти или на стеке?Хм... а что лежит в стеке? Аргументы функций?
Если в памяти, то мы их держим за смартпоинтеры?За что?
Если они ссылаются друг на друга просто, но мы их просто удалим, когда они перестанут быть нам нужны. От наличие в них ссылок друг на друга нам ни жакро, ни холодно.Проблема в том, что там, где нам перестаёт быть нужен второй объект - нам ещё нужен первый, и мы не имеем права удалять второй объект, мы не знаем, может быть, он ещё будет нужен снаружи. Чтобы не удалять такие объекты, нам надо иметь что-нибудь более продвинутое, чем твои области видимости, а именно - счётчик ссылок.
Но этот счётчик ссылок не даст нам удалить первый объект, когда мы выйдем из той области видимости, где он создан - точно так же, как он не дал нам удалить в похожей ситуации второй объект. Значит, нужно иметь что-то ещё более продвинутое, что-то, что сможет обнаруживать такие "острова". А в реальном времени это делать не получится - вот у тебя и вышел традиционный сборщик мусора.
Тогда в этом случае да, появится рекурсивная зависимость (если во всех промежуточных вопросах стоит правильный ответЯ не очень понял эти промежуточные вопросы, но похоже, что да.
но вот я только не понимаю, на фига я бы так стал делатьНет. Такие ситуации сами могут возникать в случае сложной модели (когда объекты косвенно ссылаются друг на друга; в этом цикле может быть и не два объекта, а сто и, выходит, как раз в плюсах и будет течь память - в отличие от языков со сборкой мусора, где она (пусть даже никто заранее и не может сказать, когда) всё-таки будет чиститься.
...
Но она нужна только для того, чтобы как раз плохо и сделать
В таких ситуациях проще просто сделать есть объект, за которым мы следим (и когда он нам больше не нужен - он сам пропадет а он в свою очередь, когда будет уничтожаться, заодно подчистит всю ту память, что тебе была нужна для игр с твоими перекрекстными и циклическими ссылками.Если решать эту задачу хорошо - то легче уж развязать циклические ссылки. То есть, хрен решишь.
А если не очень - то такой объект будет жить очень долго, время его жизни будет сравнимо со временем жизни программы, и никаких особых преимуществ перед "вызовем все деструкторы перед выходом" это не даст.
Кстати, никто не в курсе, на чём написан GC, скажем, в mono?
, ты название темы читал?Да. Я вижу там "C++".
И я тут говорю, что C++ - говно по сравнению с C#. И тут прибегают какие-то непонятные люди и начинают говорить, что какой-то C++0x не так уж и плох. Да ради бога, я вообще без понятия, что это за C++0x такой, но C++ - говно.
я вообще без понятия,Ключевая фраза. Ты вообще в любой теме без понятия о предмете этой темы, но упорно толкаешь свои мысли. Зачастую у тебя получается весьма смешно.
А то, что в C++ можно отстрелить себе ногу, все и так знают.Проблема в том, что в C++ ногу отстрелить гораздо легче, чем в других языках (например, те же джава и сишарп). Фактически, даже лучший в мире стрелок запросто себе эту ногу может отстрелить, об остальных и говорить нечего.
Именно поэтому я считаю C++ говном. Не нравятся мне простреленные ноги.
Ссылки стоит заменить на указатели и возложить на один из объектов заботу об удалении другого.А по-моему, стоит не сношать себе (и тем, кто за тобой это будет разгребать) мозг, и использовать язык, в котором не придётся напрямую работать с памятью.
C++0x - это название стандарта для C++Жжошь.
например, те же джава и сишарпТак вот, например, плохие стрелки отстреливают себе ноги в Java и C# гораздо чаще. Но в C# в два раза чаще, чем в Java, потому что в нём нет строгой спецификации исключений. Что на мой взгляд является минусом этого языка.
Кстати, это что, означает, что C# 3.0, LIINQ и WPF ты считаешь костылями C#?LINQ и WPF не исправляют недостатки старых версий, а добавляют новые фишки.
А все эти ваши boost-ы - именно костыли, чтобы на C++ было писать не совсем хреново, чтобы исправить недостатки C++.
Вот дженерики, появившиеся во второй - да, можно назвать костылями. Вот только между первой и второй версиями сишарпа прошли совсем не 25 лет.
C++0x - это название стандарта для C++Ну так вот теперь тебе ссылка: http://en.wikipedia.org/wiki/C%2B%2B0x
Жжошь.
C++0x is the planned new standard for the C++ programming language. It is intended to replace the existing C++ standard, ISO/IEC 14882, which was published in 1998 and updated in 2003. These predecessors are informally known as C++98 and C++03.
Ещё раз - не лезь спорить с людьми по теме, о которой ты хотя бы не погуглил.
Понимаешь, он считает, что для этого придётся написать delete руками. Но для того, чтобы ему что-то втолковать, он сначала должен понять, что Си++ сам не считает ссылки, что Си++ автоматически вызывает деструкторы, и так далее. Тогда ему можно будет показать boost::weak_ptrЕщё один читатель.
Я тут уже пару часов пытаюсь получить от кого-нибудь информацию, что произойдёт в случае с циклическими ссылками - ссылки станут указывать в никуда или объекты не удалятся.
Вы мне в разных, независимых постах отдельно говорите, что не произойдёт первого и не произойдёт второго. А что произойдёт?
Я вот не вижу, как могут и ссылки не испортиться, и объекты удалиться.
И прежде, чем что-то писать, стоит прочитать не только конкретный пост, на который отвечаешь, выдранный из контекста, но и всю нить обсуждения. А то получается спор вида XXX: "Очевидно, произойдёт либо А, либо Б. Похоже, что в данном случае произойдёт А"; YYY: "Нифига, А не произойдёт, ты ничего не понимаешь, читай книжки"; XXX: "Понятно, значит произойдёт Б"; ZZZ: "Б не может произойти, прочитай хотя бы одну книжку, прежде чем писать такой бред"; XXX: "То есть, всё-таки произойдёт А?"; YYY: "Ты что, не слушал? А произойти не может!"
Вы спорите с тем, на чём я и не настаиваю; но так и не отвечаете на мой вопрос.
use search, мать вашу
LINQ и WPF не исправляют недостатки старых версий, а добавляют новые фишки.boost не исправляет никаких недостатков, а добавляет новые фишки. Сегодня нельзя рассматривать язык без его стандартной библиотеки. И говорить о том, сколько лет прошло, тоже нельзя. 25 лет назад ни один компьютер не потянул бы GC от C# или Java, потому что их реализация GC жрёт память. Так что не надо тут ляля разводить.
А все эти ваши boost-ы - именно костыли, чтобы на C++ было писать не совсем хреново, чтобы исправить недостатки C++.
Так вот, например, плохие стрелки отстреливают себе ноги в Java и C# гораздо чаще. Но в C# в два раза чаще, чем в Java, потому что в нём нет строгой спецификации исключений. Что на мой взгляд является минусом этого языка.Всё дело в том, что плохие стрелки преимущественно считают С++ говном и на нём не пишут. Больше плохих стрелков пишет на C# или Java и поэтому чаще отсрелива.т себе ноги. Но совсем уж плохие стрелки пишут на PHP и умудряются наловить дедлоков в БД при почти нулевой нагрузке.
Ты вообще в любой теме без понятия о предмете этой темы, но упорно толкаешь свои мысли.Я не толкаю свои мысли о C++0x.
Сюда могут прийти ассенизаторы и начать чего-то говорить о сравнительных характеристиках отбросов в разных городах. Я совершенно не в теме этих отбросов - и что, я не могу что-то говорить по теме треда?
Ты сюда пришёл и начал пороть какую-то хрень про C++0x. Да, я без понятия про этот ваш C++0x, и, заметь - я ничего и не говорю про C++0x, я говорю про чистый C++.
Ну так вот теперь тебе ссылкаИ что?
Того факта, что ты жжошь, это не отменяет.
тема с циклическими ссылками обсасывалась на этом форуме как минимум один разТолько на моей памяти это было раз пять
Только на моей памяти это было раз пятьи что? форумские "теоретики" еще не наигрались?
Я тебя попытался понять и объяснить. Но ты, похоже, не пытаешься понять что тебе пишут, если там есть места, которые ты не понимаешь. Прочитай лучше пост от mkal, там все предельно ясно. Удаляется ровно тогда, когда надо
Проблема в том, что там, где нам перестаёт быть нужен второй объект - нам ещё нужен первый, и мы не имеем права удалять второй объект, мы не знаем, может быть, он ещё будет нужен снаружи. Чтобы не удалять такие объекты, нам надо иметь что-нибудь более продвинутое, чем твои области видимости, а именно - счётчик ссылок.
Но этот счётчик ссылок не даст нам удалить первый объект, когда мы выйдем из той области видимости, где он создан - точно так же, как он не дал нам удалить в похожей ситуации второй объект. Значит, нужно иметь что-то ещё более продвинутое, что-то, что сможет обнаруживать такие "острова". А в реальном времени это делать не получится - вот у тебя и вышел традиционный сборщик мусора.
В С++ наличие на объект ссылки откуда-то не мешает нам его удалить, если мы хотим. Так же в С++ нет твоих умных вещей, как подсчет ссылок. Точнее есть, но не в том понимании, в котором ты используешь. Для простоты картины представь, что у тебя есть ссылки типа А и ссылки типа В. Все свои внутренние перекрестные ссылки ты реализуешь через ссылки типа В. А сами объекты держишь через ссылки типа А. Как только ссылок типо А больше на твои объекты нет - они разом все удаляются, и им насрать на то, что на них ссылаются какие-то ссылки типа В. В С++ указатели бывают разных типов, а не одного. Возможно именно от этого непонимания все вопросы про рекурсивные зависимости.
Ещё один читатель.Я тут уже пару часов пытаюсь понять, ты уяснил, почему не нужен delete или нет? С циклическими ссылками тебе ответили уже несколько раз: мы используем boost::weak_ptr. В случае удержания двух объектов "в воздухе", они цепляются на shared_ptr за поток, что очень похоже на механизм работы Java/C#. Других вариантов не существует, даже в языке с GC не могут быть два объекта, на которые никто кроме этих объектов не ссылается. Если эта ситуация возникает в языке с GC, то они будут собраны; в Си++ эти объекты сразу удалятся. Нет, delete писать не надо.
В ответ на:
Я тут уже пару часов пытаюсь получить от кого-нибудь информацию, что произойдёт в случае с циклическими ссылками
Больше плохих стрелков пишет на C# или Java и поэтому чаще отсреливают себе ноги.Чтобы отстрелить ноги на C#, надо целенаправленно пытаться их отстрелить. Люди, отстрелившие себе ноги на C#, получили то, чего хотели. В чём проблема-то?
и умудряются наловить дедлоков в БД при почти нулевой нагрузкеИнтересно, что же это за стрелки такие умудряются наловить дедлоков при почти нулевой загрузке?
Вот при относительно существенной нагрузке, когда в каждый момент времени идёт десяток больших транзакций - уже можно. Для этого достаточно всего лишь не подумать о проблеме дедлоков в самом начале разработки проекта; и исправить это можно, хотя это и довольно трудоёмкая задача.
Да вот хз, несмотря на те треды, постоянно появляются какие-то очередные новички, которые с пеной на губах начинают утверждать, какой замечательный язык сиплюсплюс
Ты сюда пришёл и начал пороть какую-то хрень про C++0x. Да, я без понятия про этот ваш C++0x, и, заметь - я ничего и не говорю про C++0x, я говорю про чистый C++.Бля, ты уебан ещё раз. Ты понимаешь, что выше по теме ты назвал C++0x ДРУГИМ ЯЗЫКОМ, отличным от Си++? Это вообще не язык программирования, а просто стандарт для языка Си++.
Чтобы отстрелить ноги на C#, надо целенаправленно пытаться их отстрелить. Люди, отстрелившие себе ноги на C#, получили то, чего хотели. В чём проблема-то?Хрен тебе. Забыть using очень просто. Ещё проще не заметить, что кто-то где-то кидает исключение. GUI любят этим страдать: классы застревают на промежуточных состояниях. Ты вообще не написал ещё ни одного проекта в релиз, а лезешь с утверждениями.
Да, я без понятия про этот ваш C++0x, и, заметь - я ничего и не говорю про C++0x, я говорю про чистый C++.С++0x состоит из описания ядра языка и его стандартной библиотеки. Стандартная библиотека написана на С++ же. Если тебе в стандартной библиотеке чего-то не хватает, то ты можешь сам это написать или использовать написанное другими. Ядро С++ не обязано включать в себя вещи, которые можно реализовать на С++. Умные указатели, подсчёт ссылок, GC - это вещи, которые можно написать на С++. Их можно было бы включить в стандартную библиотеку (и часть из этого там есть а можно реализовать на С++ самому. Когда стандартную библиотеку стандартизировали в последний раз, вещи из boost, которые ты называешь костылями, были никому не нужны. Сейчас они нужны и в новый стандарт их включат.
То, что стандарт редко обновляется - проблема C++, но это не делает его плохим языком.
Мне, например, посрать на то, что входит в стандартную библиотеку, а что нет, т.к. в нашей фирме она не используется, а всё что нам надо для автоматического контроля памяти и ресурсов у нас реализовано на С++ в виде своей библиотеки.
На С++ можно сделать GC, а на C# - нет. Поэтому в ядре С++ GC нет, а в C# - есть.
Для простоты картины представь, что у тебя есть ссылки типа А и ссылки типа В. Все свои внутренние перекрестные ссылки ты реализуешь через ссылки типа В. А сами объекты держишь через ссылки типа А.Я понял, что есть два типа ссылок; но мне не нравится, что ты предлагаешь реализовывать потенциально циклические ссылки через тип Б. Некрасиво как-то, когда неожиданно оказывается, что там, где должен был быть объект, его нет.
Возможно именно от этого непонимания все вопросы про рекурсивные зависимости.Нет, от другого непонимания. От того, что, если у меня в одном объекте хранится другой объект, то я хочу, чтобы в любом методе первого объекта, кроме деструктора, этот другой объект существовал; а для тебя является совершенно нормальной ситуация, когда в любой момент второй объект может удалиться.
Я даже представить не могу, как реализовывать сложную логику с такими допущениями.
С циклическими ссылками тебе ответили уже несколько раз: мы используем boost::weak_ptr.Насколько я понимаю, при этом у нас второй объект может удалиться тогда, когда первый ещё существует, и где-то используется.
Если эта ситуация возникает в языке с GC, то они будут собраныТолько тогда, когда они нигде не используются.
И GC нужно время на то, чтобы найти такие "острова", на которые никто, кроме них, не ссылается. Ты либо ищешь острова, либо удаляешь абы как (т.е. не удаляешь объекты вообще или удаляешь их, когда ещё используются те, которые на них ссылаются).
Я даже представить не могу, как реализовывать сложную логику с такими допущениями.Это всё потому, что ты вообще не можешь представить себе сложную логику. В твоём примере всегда должен удерживаться хотя бы один объект. Неважно, Си++ это или C#. Как только оба объекта перестают удерживаться, так оба класса и удаляются. Неважно, Си++ или C#.
Это вообще не язык программирования, а просто стандарт для языка Си++.Будущий возможный стандарт для языка, очень сильно отличающегося от нынешнего C++ (хотя и образованного от него).
По-моему, этого достаточно для того, чтобы назвать C++0x другим языком.
Может быть потому, что они не видели за последние несколько лет ни простреленных ног, ни у себя, ни у большинства соработников? Видели только у тех, кто играет с огнем, чтобы другим всем было хорошо. И при этом есть понимание, что именно для нашей задачи просто никакой другой язык не подойдет. Более высокоуровневые языки не дадут нам ни нужных нам скоростей, ни ограничений по памяти. А на более низкоуровневых будет сильно дольше и гораздо опаснее.
Ты не понял немного. Все ссылки типа В будут рабочими всегда. Объекты удалятся, когда пропадут все (а не одна) ссыки типа А. То есть когда ни на один из объектов не будет ссылок типа А (извне они разом удалятся. До этого момента они будут существовать.
Некрасиво как-то, когда неожиданно оказывается, что там, где должен был быть объект, его нет.
Как я уже написал, ничего не удаляется, что может понадобиться.
Нет, от другого непонимания. От того, что, если у меня в одном объекте хранится другой объект, то я хочу, чтобы в любом методе первого объекта, кроме деструктора, этот другой объект существовал; а для тебя является совершенно нормальной ситуация, когда в любой момент второй объект может удалиться.
Забыть using очень просто.Ага, это действительно проблема, как тут уже говорили.
Тем не менее, в С++ простор для выстрелов гораздо шире.
Ещё проще не заметить, что кто-то где-то кидает исключение.Не надо ничего замечать (кстати, это, имхо, как раз минус джавы - что надо везде эти исключения определять, смысл исключений теряется).
Исключение летит до того места, где знают, как его обработать.
Если где-то находится критичный к изменению состояний код - он оборачивается в try..catch, в catch состояние откатывается и исключение кидается дальше. Для этого не надо смотреть, какие именно исключения могут кинуться посередине и могут ли кинуться вообще.
Ты вообще не написал ещё ни одного проекта в релиз,На C# - нет.
На управляемом языке со сборкой мусора и исключениями - да.
Насколько я понимаю, при этом у нас второй объект может удалиться тогда, когда первый ещё существует, и где-то используется.Не может. У тебя всегда есть один объект, который удерживается хотя бы текущим потоком. Этот объект держит все остальные. Один shared_ptr, много weak_ptr - это стандартная практика.
Если эта ситуация возникает в языке с GC, то они будут собраны
--------------------------------------------------------------------------------
Только тогда, когда они нигде не используются.
Перечитай мой пост ещё раз. Я говорил о том, что если возникает ситуация, когда два объекта никем не удерживаются, то независимо от языка они удаляются. Неважно, сейчас или в цикле GC.
Чем он отличается? В boost просто реализовано то, что у большинства и так уже давно есть и реализовано. Эта просто дополнительная библиотека для удобства и многие без проблем живут и без нее.
Будущий возможный стандарт для языка, очень сильно отличающегося от нынешнего C++ (хотя и образованного от него).
По-моему, этого достаточно для того, чтобы назвать C++0x другим языком.
Это всё потому, что ты вообще не можешь представить себе сложную логику.Как раз могу, в отличие от тебя.
Хотя ты, видимо, под "сложной логикой" подразумеваешь простую, обёрнутую огромной кучей workaround-ов для ситуации "ой, а объект, который мы хранили, оказывается, уже кто-то удалил".
В твоём примере всегда должен удерживаться хотя бы один объект. Неважно, Си++ это или C#. Как только оба объекта перестают удерживаться, так оба класса и удаляютсяМожно поподробнее, как именно это сделано в C++?
А именно, интересует "как только оба объекта перестают удерживаться".
В C++ при выходе из каждой области видимости запускается сборщик мусора? Насколько я понимаю, нет.
Но по твоим словам, именно так и выходит. Как только мы вышли из области видимости для последнего видимого снаружи объекта - какая-то магия понимает, что теперь та тысяча объектов, ссылающихся друг на друга, снаружи не используется, и удаляет их.
Как она это понимает и сколько на это уходит времени?
Не надо ничего замечать (кстати, это, имхо, как раз минус джавы - что надо везде эти исключения определять, смысл исключений теряется).Если не надо замечать, то это как раз минус. Ты можешь не знать о том, что вызов какой-то функции, написанной другим программистом где-то глубоко внутри кидает исключения. И поэтому ты не завернёшь простой код в try/catch с поддержкой состояния твоего объекта. А тестеры не протестируют обрыв сети, из-за которого и выкидывается исключение.... И у клиентов всё сдохнет.
Исключение летит до того места, где знают, как его обработать.
Если где-то находится критичный к изменению состояний код - он оборачивается в try..catch, в catch состояние откатывается и исключение кидается дальше. Для этого не надо смотреть, какие именно исключения могут кинуться посередине и могут ли кинуться вообще.
именно для нашей задачи просто никакой другой язык не подойдетВ задачах, где крайне критично быстродействие и потребление памяти (например, гамы, создание 3д графики итп C++ действительно лучший язык. Но это "лучший" означает, что C++ всего лишь меньшее зло, и не означает, что C++ - не говно.
Все ссылки типа В будут рабочими всегда. Объекты удалятся, когда пропадут все (а не одна) ссыки типа А. То есть когда ни на один из объектов не будет ссылок типа А (извне они разом удалятсяВсё, понял.
Можно поподробнее, как именно это сделано в C++?Если у тебя тысяча объектов ссылается друг на друга без наличия контейнера для них, то тебе надо убить себя об стену независимо от языка программирования. Если у тебя разумная агрегация, тогда тебе достаточно удерживать один объект извне. Остальные можно удерживать внутри этого объекта. (На древовидной иерархии классов удерживать будут объекты, которые стоят ниже - это хорошее правило.)
А именно, интересует "как только оба объекта перестают удерживаться".
В C++ при выходе из каждой области видимости запускается сборщик мусора? Насколько я понимаю, нет.
Но по твоим словам, именно так и выходит. Как только мы вышли из области видимости для последнего видимого снаружи объекта - какая-то магия понимает, что теперь та тысяча объектов, ссылающихся друг на друга, снаружи не используется, и удаляет их.
Как она это понимает и сколько на это уходит времени?
Всё, понял.Ага. И прикинь, мы так ни разу и не написали delete.
Все ссылки типа В будут рабочими всегда. Объекты удалятся, когда пропадут все (а не одна) ссыки типа А. То есть когда ни на один из объектов не будет ссылок типа А (извне они разом удалятсяЕсть тысяча объектов, у них друг на друга куча ссылок типа Б.
Кроме того, на один объект снаружи есть ссылка типа А.
Эта ссылка удаляется. Что именно теперь происходит? На то, чтобы понять, что действительно надо что-то удалить, и какие именно объекты надо удалить, по-моему, должна уйти куча времени.
Ты можешь не знать о том, что вызов какой-то функции, написанной другим программистом где-то глубоко внутри кидает исключения. И поэтому ты не завернёшь простой код в try/catch с поддержкой состояния твоего объекта.Если я что-то вызываю в этом простом коде, и меняю состояние (которое в случае ошибки надо откатить назад) - я оберну простой код в try..catch, и не буду смотреть, кидает сейчас там что-нибудь исключение или нет.
Есть тысяча объектов, у них друг на друга куча ссылок типа Б.Если у тебя тысяча объектов, то они хранятся в контейнере независимо от языка. И удаляться они будут все сразу. Кроме того, реализация CRT в VS2008 создаёт и удаляет объекты быстрее, чем GC в C# 2.0
Кроме того, на один объект снаружи есть ссылка типа А.
Эта ссылка удаляется. Что именно теперь происходит? На то, чтобы понять, что действительно надо что-то удалить, и какие именно объекты надо удалить, по-моему, должна уйти куча времени.
И прикинь, мы так ни разу и не написали delete.И, похоже, начали запускать сборщик мусора при каждом выходе из какой-нибудь области видимости.
Если я что-то вызываю в этом простом коде, и меняю состояние (которое в случае ошибки надо откатить назад) - я оберну простой код в try..catch, и не буду смотреть, кидает сейчас там что-нибудь исключение или нет.То есть ты будешь за этим следить "вручную". Надо это, или не надо - поифигу. А в Java мы будем делать это тогда и только тогда, когда это надо.
И, похоже, начали запускать сборщик мусора при каждом выходе из какой-нибудь области видимости.Мы не запускаем сборщик мусора. У нас его нет. При выходе из области видимости у нас только вызываются деструкторы.
Если у тебя тысяча объектов, то они хранятся в контейнереТысяча однотипных в большинстве случаев - да.
Тысяча разнотипных, часть из которых может понадобиться в будущем - нет.
Самое интересное, что не надо ). Все происходит мгновенно. Автоматически (а не заметили в какой-то момент, что ссылок больше нет) запускается процесс очищения памяти. Если описывать, как мой пример, то на все объекты есть еще ссылки типа С (которые скрыты и их не видно, они выставляются и убираются автоматически и по ним ясно что именно надо удалить. Они как раз появляются и пропадают вместе с объектом. Если в понятиях , то контейнер заметил, что то, что он хранит, больше никому не надо и просто все удаляет. Кстати, ничто не мешает в таком контейнере иметь совершенно разные по сути объекты.
Эта ссылка удаляется. Что именно теперь происходит? На то, чтобы понять, что действительно надо что-то удалить, и какие именно объекты надо удалить, по-моему, должна уйти куча времени.
Тысяча разнотипных, часть из которых может понадобиться в будущем - нет.Тысяча разнотипных объектов, которые ссылаются друг на друга, имеют базовый класс. Если же ты собрался в каждом из тысячи прописывать конкретные типы, то лучше сразу убей себя об стену. Базовые классы хранятся в контейнере, и далее по тексту. Быстро удалять и создавать контейнеры с объектами Си++ тоже умеет.
Базовые классы хранятся в контейнереЧуть-чуть уточню: указатели на базовые классы. Для хранения указателей в контейнерах в boost даже придумали ptr_{vector, set, ...}.
Мы не запускаем сборщик мусора. У нас его нет. При выходе из области видимости у нас только вызываются деструкторы.Деструкторы чего?
Для того, чтобы понять, чьи деструкторы вызывать (если вообще надо что-то вызывать) - надо запустить что-то вроде сборщика мусора, чтобы оно увидело, что на такую-то группу объектов существуют ссылки только типа Б.
Кстати, насколько я понимаю, в коде вроде
class CRegistry
...
public void delete(class, id) {
if(isSet(this.hStorage[class][id] unset(this.hStorage[class][id]);
}
в вызове unset (точнее, том, что будет написано вместо этого в плюсах) создастся А-ссылка, затем удалится Б-ссылка, и потом удалится А-ссылка? Или А-ссылок не будет? Во втором случае всё оказывается ещё хуже, "острова" придётся определять ещё чаще.
Чуть-чуть уточню: указатели на базовые классы.Я выразился обще, потому что говорил про любой язык.
Базовые классы хранятся в контейнереАга, и ручками всё контролировать
контейнер заметил, что то, что он хранит, больше никому не надо и просто все удаляетПроблема появляется, когда часть объектов никому, кроме их самих, не нужна; а часть - нужна. И никто заранее не знает, что будет нужно, а что - нет.
Можно, конечно, и выстроить тут всё, как надо... но гораздо легче положиться на сборщик мусора.
Для того, чтобы понять, чьи деструкторы вызывать (если вообще надо что-то вызывать) - надо запустить что-то вроде сборщика мусора, чтобы оно увидело, что на такую-то группу объектов существуют ссылки только типа Б.Для того, чтобы понять, чьи деструкторы вызывать, достаточно лишь раскрутить стек. И ещё деструкторы вызываются во время удаления объекта. Нас это мало волнует. boost::smart_ptr ведёт подсчёт сильных и слабых ссылок сам, в своих деструкторах и конструкторах. Нет, это не ведёт к тормозам или отжиранию памяти.
Ага, и ручками всё контролироватьВремя жизни объектов будет контролировать контейнер. Представь себе, он тоже умеет вызывать деструкторы хранимых объектов.
Время жизни объектов будет контролировать контейнер.Я думал, ты имеешь в виду самописный контейнер.
Про то, что получится в случае простого контейнера, который умеет только удалять всё, я уже написал.
Проблема появляется, когда часть объектов никому, кроме их самих, не нужна; а часть - нужна. И никто заранее не знает, что будет нужно, а что - нет.У тебя что, архитектура программы представляет собой не дерево, а звёздочку? Если "нужная часть" из тысяч объектов, которые ссылаются друг на друга, отдаётся вовне, то ты на самом деле отдаёшь наружу точно такой же контейнер. И если ты будешь работать с этими объектами по одному, без пулинга, то C# начнёт тормозить гораздо раньше, чем Си++.
достаточно лишь раскрутить стекПричём тут стек?
boost::smart_ptr ведёт подсчёт сильных и слабых ссылок сам, в своих деструкторах и конструкторах.Есть десять тысяч объектов, у каждого из них - 0 сильных и 10 слабых ссылок. Ну и ещё куча объектов есть, с сильными ссылками.
Как понять, какие объекты из этих десяти тысяч удалять? Как тебе тут поможет твой подсчёт ссылок?
Ты знаешь, что совсем недавно на один объект из этих десяти тысяч была и сильная ссылка, и как раз сейчас её удалили. Как это тебе поможет? Тебе всё равно надо будет потратить немало времени, чтобы понять, что этот объект сейчас находится в острове из тысячи элементов (и каких именно) или что он косвенно всё-таки связан с одним из тех объектов, на которые есть сильные ссылки.
Про то, что получится в случае простого контейнера, который умеет только удалять всё, я уже написал.Блин, ну ты головой-то подумай. Тебе тут три часа втирали разные умные вещи. Если ты хочешь отрезать кусок графа, то ты его отрежь и верни с другим контейнером. Что на Си++, что на C# одна малина.
Про то, что получится в случае простого контейнера, который умеет только удалять всё, я уже написал.Может я во сне плохо соображаю, но что мешает заюзать контейнер, содержащий shared_ptr?
Я видимо забыл написать, что те объекты, на которые нет ссылок ни типа A ни типа B чудесным образом сами тоже пропадают. Причем в момент, когда пропала ссылка, а не в момент, когда сборшик мусора решит, что пора ему поработать.
Проблема появляется, когда часть объектов никому, кроме их самих, не нужна; а часть - нужна. И никто заранее не знает, что будет нужно, а что - нет.
и сильно менее надежно ).
... но гораздо легче положиться на сборщик мусора.
PS
У тебя просто немного более узкое понимание, что есть ссылка. Указатели в С++ более свободные. У них есть гибкость, а ты пытаешься привести пример, которые не разрешается в твоих понятиях ссылок при отсутствии сборщика мусора. Если писать немного более низкоуровнево, чем советует Майк, то это нормально, что в некоторые моменты времени ты на часть объектов вообще не хранишь ссылок (в твоем понимании). А потом, когда они нужны, достаешь их из ниоткуда
Причём тут стек?При том, что для вызова деструкторов не надо считать ссылки. Не путай момент уделения объекта с хипа и вызов деструктора.
Есть десять тысяч объектов, у каждого из них - 0 сильных и 10 слабых ссылок. Ну и ещё куча объектов есть, с сильными ссылками.
Как понять, какие объекты из этих десяти тысяч удалять? Как тебе тут поможет твой подсчёт ссылок?
Ты знаешь, что совсем недавно на один объект из этих десяти тысяч была и сильная ссылка, и как раз сейчас её удалили. Как это тебе поможет? Тебе всё равно надо будет потратить немало времени, чтобы понять, что этот объект сейчас находится в острове из тысячи элементов (и каких именно) или что он косвенно всё-таки связан с одним из тех объектов, на которые есть сильные ссылки.
Десять тысяч объектов - это предмет для пулинга в любом языке. Они хранятся в контейнере и друг на друга указывают голыми указателями. А вообще мы просто берём реализацию графа.
Поэтому давай попроще. Есть два объекта. Один внизу дерева классов, другой вверху. Первый держит shared_ptr на второй. Второй держит weak_ptr на первый. Кто-то держит shared_ptr на первый. Как только удаляется первый, так сразу же удалится второй. Всё. Времени на это тратить не надо.
Всё, понял.Локс сделал невозможное?
На С++ можно сделать GC, а на C# - нет. Поэтому в ядре С++ GC нет, а в C# - есть.путаешь ms .net и c#.
чего такого нет в C#, что необходимо для написания GC?
Блин, ну ты головой-то подумай.Ты совершенно зря пытаешься говорить с Пенартуром как с нормальным человеком. Если уж на то пошло, ты вообще зря пытаешься говорить с Пенартуром. Это и так довольно бессмысленное времяпрепровождение, а уж обсуждать С++, с которыми он знаком сугубо теоретически...
Я, наверное, имею больше опыта проникновения во внутренний мир ненормальных людей вроде Пенартура и могу для тебя расшифровать его фразу про "тысячу ссылающихся друг на друга разнотипных объектов".
Представь какую-нибудь гуёвую прогу для редактирования чего-нибудь, написанную идиотом. Полным, невозможным, фантастическим идиотом, которого нельзя на километр подпускать к программированию.
Ну, там есть листбокс, ссылающийся на кучу объектов и достающий из них данные, есть какие-то эдит-контролы, тоже ссылающиеся на некоторые из этих объектов, есть кнопки Add, Delete, Import и Export, сотворяющие нечто с объектами. В том числе и с теми же, которые в этот момент редактируются. Некоторые объекты могут иметь ссылки на другие объекты, эти ссылки можно редактировать. Некоторые объекты самостоятельно подписываются на эвенты эдит-контролов.
И нет никакого централизованного лайфтайм менеджера, который следит за тем, чтобы при удалении объекта из общего пула не осталось ссылающихся на него объектов, например. Поэтому через пять минут работы программы в ней накапливается тысяча невидимых из главного листбокса объектов, на которые кто-нибудь ссылается. Ну, текут ссылки, текут. Те же эвенты - подписался, забыл отписаться, всё, ссылка утекла. А может там есть ещё один специальный менеджер для экспорта объектов, который тоже сохраняет ссылки. Некоторые. Случайные, фактически. В самом деле, почему GC позволено вызывать финалайзеры недетерминированно, а программа, недетерминированно сохраняющая объекты в файл, считается глючной? Это дискриминация!
Вот наш милый Пенартурчег, с которым ты зачем-то пытаешься разговаривать как с нормальным человеком, считает, что хороший язык должен позволять построить подобную систему, причём так, чтобы когда наивный юзер редактирует объект, который он по логике уже удалил, всё замечательно продолжало работать, просто при сериализации изменения не сохранились бы. Или сохранились, но тоже в специальном невидимом обычными методами куске графа. А чо, нормально.
Ты, по ходу, даже представить себе не можешь, что кто-то может так видеть мир, поэтому неправильно отвечаешь на его вопросы. У тебя-то есть чёткое представление о том, кто чей хозяин и когда кто удаляется, не столько потому, что ты боишься утечек памяти, сколько потому, что порядок должен быть. Если есть порядок, то, в качестве побочного эффекта, всё удаляется своевременно и ничего никуда не утекает.
Вот, в рамках своего представления ты пишешь что-то про weak_ptr, ну, ты ведь точно знаешь, куда их нужно поставить и что произойдёт. А Пенартур наоборот не может представить, что у кого-то прога может быть упорядочена, и читая твои слова представляет свою тыщу макаронистых объектов, у которых часть сырых пойнтеров зачем-то заменена на бустовские структуры. И, естественно, не понимает, как это поможет избежать... ну, чего-нибудь избежать, короче.
Если у тебя тысяча объектов ссылается друг на друга без наличия контейнера для них, то тебе надо убить себя об стену независимо от языка программирования. Если у тебя разумная агрегация, тогда тебе достаточно удерживать один объект извне. Остальные можно удерживать внутри этого объекта. (На древовидной иерархии классов удерживать будут объекты, которые стоят ниже - это хорошее правило.)в больших проектах, особенно в интеграционных совсем не очевидно, кто будет держать этот самый контейнер, или кто будет держать вышестоящие объекты.
Возьмем, например, Excel или Html Dom, или любой другой объемистый объектный граф - и есть модуль, который работает с частью этого графа.
какую ссылку этот модуль должен держать - на ту часть с которой работает? на весь DOM?
что-то еще?
Проблема понятна? пояснить?
что хороший язык должен позволять построить подобную систему, причём так, чтобы когда наивный юзер редактирует объект, который он по логике уже удалил, всё замечательно продолжало работать, просто при сериализации изменения не сохранились бы.интернет вроде работает по такой схеме, и ниче живет вроде отлично.
а вот "интернеты" построенные по жесткой схеме почему-то не прижились.
afaik, большие (вернее, БОЛЬШИЕ) проекты невозможно сделать по той централизованной схеме, которую ты предлагаешь.
1. ресурс - конечен
2. ресурс - требует детерминированное удаление (следует из п.1)
3. при чистке ресурсов нельзя полагаться на существующие GC (т.к. GC - недетерминирован и п.2)
4. если кто-то использует ресурс - то он сам по себе становится ресурсом (из п.2)
5. при работе с ресурсами приходится использовать метод подсчета ссылок (т.к. бывают ссылки много к одному, и да более сложные методы провисают по скорости, и да нам же нужен п.2)
6. есть проблема с циклическими ссылками (из п. 5)
И все эти проблемы есть и в C#, и в C++, но... большую часть объектов составляют всякие вспомогательные объекты: строки, точки, числа, коллекции, которые используют лишь один вид ресурса - память, соответственно как только память перестает быть ресурсом, то и вся толпа этих объектов тоже перестает быть ресурсами (см. п.4).
итого:
разница между программированием на C++ и C# лишь в том:
что при программирование на C++ приходится постоянно прокручивать в голове, что весь миллион используемых объектов - это ресурсы, и соответственно при каждом чихе проверять все перечисленные 6 пунктов,
на C# тоже необходимо крутить мысли про ресурсы - только уже про десяток-сотню-десятки тысяч основных объектов, и развязывать себе руки при работе с остальным миллионом вспомогательных объектов.
ps
[to penartur]
да, на C# тоже есть проблема с циклическими ссылками.
да, при написании на C++, используя небольшой набор "культурных" правил, можно почти не думать о том, что память это ресурс
[to all]
да, C++ - очень страшный мастодонт и должен умереть (причем отсутствие GC лишь небольшое неудобство на фоне остальных проблем C++)
Возьмем, например, Excel или Html Dom, или любой другой объемистый объектный граф - и есть модуль, который работает с частью этого графа.Понимаешь, здесь всё время идёт речь о графах, о представлении данных. (И правильно, если у тебя тяжёлые кольцевые ссылки внутри обычной архитектуры, то такую архитектуру лучше выкинуть на помойку.) А в хорошей архитектуре такие данные хранятся и обрабатываются отдельно, для этого есть много известных механизмов.
какую ссылку этот модель должен держать - на ту часть с которой работает? на весь DOM?
что-то еще?
Проблема понятна? пояснить?
При выделении части графа никто тебе не мешает либо отрезать от него кусок и прицепить за shared_ptr, либо оставить его в контейнере и работать с частью этого графа через контейнер, либо взять shared_ptr конкретной вершины и выкинуть ненужные. Неважно, есть ли GC в языке, но если ты работаешь с конкретной вершиной графа, где все объекты связаны, то этот граф не будет удалён до тех пор, пока ты не завершил работу с этой вершиной.
Я не спорю, что граф - это один из немногих примеров, когда GC будет немного удобнее. Но не такой, чтобы кричать на каждом углу об утечках памяти в Си++
Кстати, Excel или DOM - это плохой пример, потому что есть их реализация в COM, где как раз есть проблемы с кольцевыми указателями, из-за отсутствия слабых указателей. Но ведь реализация DOM есть, и работает она не с черепашьей скоростью.
да, C++ - очень страшный мастодонтНу кто бы мычал про мастодонтов. C# имеет более чем 75 ключевых слов.
может в фак раздела поместить?
Но ведь реализация DOM есть, и работает она не с черепашьей скоростью.если уж зашла речь про DCOM, ты реализацию агрегации на DCOM-е видел?
а ведь ты ранее говорил, что агрегация делается довольно очевидно, и можно обойтись weak_ptr.
ps
вообщем, я только хочу отметить, что одними shared_ptr и weak_ptr в большом проекте не обойтись
Ну кто бы мычал про мастодонтов. C# имеет более чем 75 ключевых слов.я больше не про сам язык, я больше про C++-окружение(необходимость наличия исходников для работы с бинарным модулем, однопроходность, прямой доступ к памяти как основной режим, макросы уровня препроцессора, отсутствие byte-кода и т.д.)
у C++, как у языка, есть всего несколько мелких недостатков (навскидку - не различает, когда имя это класс, а когда переменная, отсутствие всякого мелкого синтаксического сахара и т.д.)
да, на C# тоже есть проблема с циклическими ссылками.Да , а какая? Или ты про что-то еще...
я читал Рихтера, там он говорил, что в .NET собщик мусора не использует подсчет ссылок, а размечает "живые" объекты начиная с "корней" (все текущие живые локальные переменные-ссылки во всех потоках, ...). Соответственно, если есть 2 объекта, которые друг на друга ссылаются, но на них уже никто не ссылается, то эти 2 объекта gc не разметит и будет соответсвенно считать "мертвыми".
Да , а какая? Или ты про что-то еще...про что-то еще
форма ссылается на таймер, таймер ссылается на форму - жить будет вечно
я читал Рихтера, там он говорил, что в .NET собщик мусора не использует подсчет ссылокэто ты про просто-объекты, а речь шла про объекты-ресурсы
просто-объекты, как я уже выше говорил, ресурсом не являются, и с ними проблем нет.
я в С# не бум бум, а почему вечно? (если писать не влом)
это ты про просто-объекты, а речь шла про объекты-ресурсыааа, это я помню, что том какая-то засада получается, помнится я для себя сделал вывод, что именно для объектов-ресурсов всегда надо юзать using
а ну тогда ясно
Рано или поздно до этой формы с таймером у gc руки доберутся и он их начнет удалять, в этот-то момент и будут освобождены системные ресурсы (ну конечно, до того как gc их удалит может всякое произойти, хоть deadlock, хоть нехватка сист ресурсов, и поэтому так писать нельзя конечно, но это уже другая проблема).
---
Не уследил за полётом мысли, поясни, пожалуйста.
Возьмем, например, Excel или Html Dom, или любой другой объемистый объектный граф
---
Я хочу сказать, что какой-то способ контроля за целостностью структуры тебе всё равно понадобится. _Особенно_ если у тебя граф действительно большой и сложный. Это вообще тема отдельного холивара, который уже был когда-то: про fail fast. Нормальна ли ситуация, когда твой отдельный обработчик работает с частью графа, которую кто-то в другом месте уже отрезал от всего графа? Что лучше, если этот обработчик зацепился за неё каким-нибудь weak_ptr и словил эксепшен в такой ситуации, или если всё прошло на вид нормально, но данные безнадёжно рассинхронизировались и это обнаружится на следующий день, когда юзер откроет сохранённый документ и обнаружит, что всё, нажитое непосильным трудом, куда-то пропало?
Не, понятно что есть определённый оптимальный уровень паранойи, и лично для меня он комфортней реализуется на шарпе, но всё же в определённых ситуациях плюсы окажутся если не удобней, то, по крайней мере, не намного неудобней. (в работе с памятью, в смысле!)
большую часть объектов составляют всякие вспомогательные объекты: строки, точки, числа, коллекции, которые используют лишь один вид ресурса - память
---
Только учитывай, что 90% этих объектов, которые в шарпе выделяются в хипе и собираются GC, в плюсах выделяются на стеке или автоматически освобождаются в деструкторе. Тут разве что эффективность страдает в некоторой мере, ну, когда ты в плюсах возвращаешь std::string, например. И то, copy on write по идее эту проблему должен решать.
Кстати! , дай-ка ссылочку в подтверждение того, что "реализация CRT в VS2008 создаёт и удаляет объекты быстрее, чем GC в C# 2.0". Что-то этого не может быть, потому что не может быть никогда, по-моему.
Пиздец говно эти ваши плюсы.
Когда же разработчику думать о содержательной части, если всё своё время он будет тратить на работу с памятью?
пиздец говно ваш императивный цешарп, когда вы по-человечески, без индексов, не можете организовать итерацию списка по первым двум элементам.
пиздец говно ваш императивный цешарп, когда вы по-человечески, без индексов, не можете организовать итерацию списка по первым двум элементам.ась?
или я чего не понял или это на всех языках одиакого делается
Что это такое? Код в студию.
act [x] = x
act [x,y] = x*y
act (x:y:z:xs) = x+(x+y)*z + act (y:z:xs)
таймер регистрируется в "системе", чтобы получать тики, поэтому GC считает, что внешняя ссылка на остров из таймера и формы - есть.
и соответственно, приходится самим думать - когда таймер разрегистрировать из системы.
ps
есть метод, чтобы ссылки на таймер от "системы" не было, но там появляется другая проблема - что таймер будет прибиваться, когда мы этого не хотим.
чтобы посмеяться могли не только юзеры флокала
уверен - это будет бестселлер
"Основны панельного билдинга на PHP"
итого:Если заменить в этом тексте Си++ на Си, тогда он становится верным. Иначе я с тобой не согласен. Какие 6 пунктов надо помнить при программировании на Си++, если пункт 3, например, про GC? Почему я должен думать про пункт 2, если вызов деструктора Си++ и так детерминирован?
разница между программированием на C++ и C# лишь в том:
что при программирование на C++ приходится постоянно прокручивать в голове, что весь миллион используемых объектов - это ресурсы, и соответственно при каждом чихе помнить все перечисленные 6 пунктов,
на C# про ресурсы необходимо крутить мысли про ресурсы - только уже про десяток-сотню-десятки тысяч основных объектов, и развязывать себе руки при работе с остальным миллионом вспомогательных объектов.
если уж зашла речь про DCOM, ты реализацию агрегации на DCOM-е видел?Агрегация на COM и агрегация в ООП - это совсем разные вещи.
а ведь ты ранее говорил, что агрегация делается довольно очевидно, и можно обойтись weak_ptr.
ps
вообщем, я только хочу отметить, что одними shared_ptr и weak_ptr в большом проекте не обойтись
Агрегация в смысле ООП делается очевидно через weak_ptr.
У меня вот уже второй большой проект на Си++, кстати первый крутится в релизе 24/7/365. И я обхожусь только shared_ptr и weak_ptr.
, дай-ка ссылочку в подтверждение того, что "реализация CRT в VS2008 создаёт и удаляет объекты быстрее, чем GC в C# 2.0".Ссылочки нет. Написали два проекта. В одном большом цикле создавали массив из объектов, потом заполняли его в другом большом цикле. Тестировать, естественно, в Release. Без инлайна и с CRT проверками работает медленнее.
На самом деле я был удивлён результатом. Это привело к тому, что я несколько раз пробежался по коду. Так вот внутри класса C++ конструировался массив int[16] + for на забитие нулями, в шарпе стоял new int[16]. Я изменил на new int[16] и вызов delete, тогда языки примерно сравнялись. Когда я выкинул все члены классов в обоих языках, тогда Си++ проиграл несколько секунд на миллиардах объектов.
в такой трактовке все императивные языки сосут
конечно. Только я отвечал пенартуру, который в последнее время постоянно имеет ввиду неебеческую крутость цешарпа.
private double act(List<Double> l) {
if (l.size == 1) {
return l.iterator.next;
}
Iterator<Double> it = l.iterator;
double x = it.next;
double y = it.next;
if (l.size == 2) {
return x * y;
}
double z = it.next;
return x + (x + y) * z + act(l.subList(1, l.size;
}
var a = new[] { 1.0, 2.0, 3.0 };
var result = a.Aggregate(new { x = 0.0, y = 0.0, z = 0.0, res = 0.0 }, (a, val) =>
{
a.x = a.y; a.y = a.z; a.z = val;
a.res += a.x + (a.x + a.y) * a.z;
return a;
}).res;
Только у тебя начальные условия неестественные, мне их влом обрабатывать.
Хотя, конечно, мне в последнее время начало не хватать статически типизированных туплов или чего-то в этом роде. Чтобы нормально делать генерик функции с переменным количеством разнотипных параметров и всё такое.
: а, ну так неинтересно, ты что. Создать кучу объектов любой лох может. Веселуха начинается когда ты объекты то создаёшь, то удаляешь, в случайном порядке. Тогда бедный аллокатор начинает бродить по памяти в поисках свободных кусочков, а деаллокатор — пытаться объеденить свежеудалённый кусочек с соседними, если они тоже свободны. И зрелище это печально.
Какие 6 пунктов надо помнить при программировании на Си++, если пункт 3, например, про GC? Почему я должен думать про пункт 2, если вызов деструктора Си++ и так детерминирован?вот эти самые 6 пунктов
1. да, обязательно надо использовать смартпоинты
2. да, то что идет в стандартной поставке - это фигня, а не смартпоинты, надо либо брать boost, либо писать свои
3. да, и еще раз, надо обязательно использовать смарт-поинты, т.к. если объект утек, то это навсегда
4. да, есть либы, которые смартпоинты не используют, но вы все равно как-нибудь смартпоинты при использовании такой либы используйте.
5. да, кстати смарт-поинтов - не один вид, а целых три: auto_ptr, shared_ptr, weak_ptr. ок, хорошо два - shared_ptr и weak_ptr, но при стыковке с чужими либами - их скорее всего будет больше, или будут такие же, но со своими названиями
6. да, еще раз на всякий случай, надо обязательно использовать смарт-поинты
Это что за уродство? Функциональное программирование глазами создателей цешарпа? Не, мы идём своей дорогой, а вы - туда же, куда и перл.
вот эти самые 6 пунктовЯ ничего не понял. Как то, что ты перечислил, ЗАСТАВЛЯЕТ меня ДУМАТЬ о ресурсах? Лично я о них не думаю, я пишу всё на boost::smart_ptr, который входит в новый стандарт Си++ Тот факт, что смарт поинтеров у нас три не напрягает даже одного нейрона в моём мозгу. В то время как при разработке на шарпе я всё время держу в голове пункт на счёт исключений и using.
Стыковки с чужими либами я даже обсуждать не хочу. Чужие либы в 98% случаев гавно. Это больная тема для любого языка. Впрочем, никаких препятствий использовать смарт поинтеры с чужими либами я не вижу.
Стыковки с чужими либами я даже обсуждать не хочу. Чужие либы в 98% случаев гавно. Это больная тема для любого языка.при использовании C++ я был с тобой согласен.
но при использовании C# почему-то уже нет...
кстати, даже еще в старом дельфи не согласен, что чужие либы - гавно.
как ты думаешь, с чем это связано?
но при использовании C# почему-то уже нет...1. С разным мнением по поводу того, что такое качественная либа.
кстати, даже еще в старом дельфи не согласен, что чужие либы - гавно.
как ты думаешь, с чем это связано?
2. С тем, что Си++ де факто используют те, кто программирует дома за ужином.
3. С персональными предпочтениями по языку программирования.
1. мелкие ошибки в C# или в том же Delphi менее критичны, чем в C++
2. в C# и Дельфи есть нормальная поддержка бинарных либ.
есть более главные причины:Ты уже заговорил про удобство создания либы. Не вижу, почему мне было бы труднее создать Си++ библиотеку, чем C#. Конечно, если есть опыт, так как всегда труднее сделать то, чем ты меньше всего занимался.
1. мелкие ошибки в C# или в том же Delphi менее критичны, чем в C++
2. в C# и Дельфи есть нормальная поддержка бинарных либ.
Ошибки в Delphi не только критичны, но и достаточно часто встречаются, потому что в нём нет автоматического вызова деструкторов.
Ошибки в C# не приводят ни к чему хорошему. Два с половиной года разработки GUI под DevExpress меня в этом убедили. Возникло непредвиденное исключение, банальный NULL pointer, и GUI класс подвис в неопределённом состоянии, программа выдала диалог "блабла обратитесь к разработчикам" и перестала работать. Бывало, что от таких "менее критичных ошибок" не удавалось даже её закрыть. Конечно, это всё от того, что GUI часто пишут непрофессиональные разработчики. Но с точки зрения конечного пользователя подобный NULL pointer что на Си++, что на C# приводит к одинаковому результату: неработоспособность программы, потеря данных.
Вообще всё это уже вне темы обсуждения. Я так и не понял, почему мне надо думать о каких-то шести пунктах, когда я пишу на плюсах. У нас прекрасно работает принцип RAII, что в блоке кода, что в дереве объектов. Поэтому я склоняюсь к тому, что на C# или Java (в этом языке тяжелее всего) надо всё время думать про ресурсы, а на Си++ не надо. Только не стоит понимать мои слова как абсолютную точку зрения, я понимаю разные аргументы и соглашаюсь, что разные языки не лишены недостатков. Но я просто категорически не согласен с подходом, когда "у C# всё хорошо, а у C++ всё плохо", потому что этот подход лишён смысла.
Если ты хочешь отрезать кусок графа, то ты его отрежь и верни с другим контейнеромЯ не знаю, какой кусок графа отрезать и что вообще надо что-то отрезать. Я предпочитаю переложить эту заботу на плечи сборщика мусора, а самому заниматься действительно важными вещами.
Я видимо забыл написать, что те объекты, на которые нет ссылок ни типа A ни типа B чудесным образом сами тоже пропадают.Это и так понятно.
Вот только к процитированной тобой фразе отношения не имеет.
я вот начал штучку писать для твого примера, этакий сахар в функциональном стиле, по типу статьи в соседней теме
не успел отладить, с работы ушел, завтра доделаю покажу
в .NET собщик мусора не использует подсчет ссылок,Странно.
Было бы логичнее, если бы использовались оба подхода, во многих случаях подсчёт ссылок тоже сработает, и уж точно он будет быстрее GC.
act [x] = xА по-русски?
act [x,y] = x*y
act (x:y:z:xs) = x+(x+y)*z + act (y:z:xs)
Чужие либы в 98% случаев гавноКак же так, ведь C++ рулит!
Это больная тема для любого языкаПредставь себе, "98%" - не для любого.
С тем, что Си++ де факто используют те извращенцы, кто программирует дома за ужином.
Возникло непредвиденное исключение, банальный NULL pointerА разве, если не использовать unsafe-код и аккуратно писать конструкторы, такое может произойти?
struct Vector3D
{
public double X, Y, Z;
public static Vector3D operator*(Vector3D vec, double mul)
{
return new Vector3D{ X = this.X * mul, Y = this.Y * mul, Z = this.Z * mul };
}
}
var vec = new Vector3D{ X = 1, Y = 1, Z = 1};
var result = vec * 2.0;
как сделать на хаскеле, чтобы последний оператор работал?
Я хз про хаскель, но то, что ты спрашиваешь - всего лишь синтаксический сахар. Запись вида vec*2.0 ничем принципиально не отличается от vec.getMultipliedBy(2.0 а вот запутать человека, который ожидает совсем другого поведения от * - может.
Собственно он написал про один сахар, я пишу ему про другой.
Кстати, насколько я знаю, в этом случае разница будет далеко не на пару строк.
Насколько я знаю, в таких случаях используют оператор (*>) или (*.) или еще что-нибудь.
А для перемножения матриц там какой оператор?
матрицы вроде подходят под стадартный Num
Молодец, возьми себе с полочки какашку. Зато у вас хвостовая рекурсия не оптимизируется. А из-за таких вот "перегрузок" ещё геморно делать вычислитель расширений не хвостовых рекурсивных функций.
Как же так, ведь C++ рулит!Представь себе, для любого.
В ответ на:
Это больная тема для любого языка
Представь себе, "98%" - не для любого.
Я не знаю, какой кусок графа отрезать и что вообще надо что-то отрезать. Я предпочитаю переложить эту заботу на плечи сборщика мусора, а самому заниматься действительно важными вещами.Не путай понятия. Каким образом сборщик мусора должен догадаться, какие из объектов, которые ссылаются друг на друга ему удалить, а какие ты хотел продолжать использовать? Очевидно, чтобы продолжать использовать только часть этих объектов, тебе бы пришлось удалить ссылки между ними и другими объектами в графе. Что на Си++, что на C# эти задачи абсолютно идентичны.
И вообще пора переводить спор в практическое русло. Напиши-ка нам код этого самого графа, и как ты видишь процесс использования только некоторых из его узлов, и в какой момент времени по-твоему будут удалены неиспользуемые узлы. Короче, код ужасного графа в студию!
Очевидно, чтобы продолжать использовать только часть этих объектов, тебе бы пришлось удалить ссылки между ними и другими объектами в графе.Да. Но ты тут, насколько я понял, предлагаешь затем руками разделять граф на две компоненты, одна из которых мне нужна, а другая - нет. В C# делать это руками мне не нужно.
Представь себе, для любого.Нет. Только для тех языков, где даже гуру, задумавшийся о чём-то другом в неподходящий момент, случайно выстрелит себе в висок.
Да. Но ты тут, насколько я понял, предлагаешь затем руками разделять граф на две компоненты, одна из которых мне нужна, а другая - нет. В C# делать это руками мне не нужно.Ничего я не предлагаю. Я предлагаю точно так же эти объекты отвязать.
А вообще давай поступим проще. Сделаем реализацию графа: ты тупо на C# (ведь там же реализация в лоб рулит, как ты утверждаешь а я на Си++ Дальше создадим... нет не 10к, давай сразу 500к вершин, и рандомом свяжем каждую вершину с десятком других. После чего будем обходить граф вширину 1кк раз. Затем разрежем этот граф на графы, в каждом из которых будет по 10к вершин, ты ведь хотел продолжать работать с "частью вершин". Всю эту логику мы запихаем в функцию, которую будем вызывать в цикле 1к раз. Затем мы сначала убедимся, что в Си++ память никуда не утекла. Потом мы убедимся, что время работы тупо написанной (а ты именно так предлагаешь делать граф) программы на C# просасывает программе на Си++. И ещё мы поймём, что C# отжирает памяти в десятки раз больше. Мне просто очень интересно, куда тогда денутся твои аргументы в пользу невзъебенной крутости C#?
Давай напишем код, а то спор без практической основы с неграмотным человеком, мне начал уже надоедать.
Возникло непредвиденное исключение, банальный NULL pointerА разве ты хотел о чём-то думать, пока программируешь? NULL pointer exception - самое, наверное, частое исключение, которое летит в программах на C#/Java.
А разве, если не использовать unsafe-код и аккуратно писать конструкторы, такое может произойти?
Нет. Только для тех языков, где даже гуру, задумавшийся о чём-то другом в неподходящий момент, случайно выстрелит себе в висок.Себе в висок ты выстрелишь на любом языке. Ни один язык тебя не спасёт от ошибок, Си++ тут совершенно не при чём. Если ты этого не понимаешь, то это означает, что ты не выполнил ни одного серьёзного проекта. Из моего опыта работы, память начинает утекать в программах на языках с GC раньше и такие проблемы там встречаются чаще, чем на Си++, потому что новички всерьёз рассчитывают, что язык программирования спасёт их от всех бед.
NULL pointer exception - самое, наверное, частое исключение, которое летит в программах на C#/Java.Можно пример, когда указанные мной условия соблюдены и летит этот самый null pointer exception?
Мне что-то ничего, что может его породить, в голову не приходит.
Сделаем реализацию графаАга, а ещё лучше - рассмотрим шарообразного коня в вакууме.
а: ты тупо на C# (ведь там же реализация в лоб рулит, как ты утверждаешь а я на Си++ Дальше создадим... нет не 10к, давай сразу 500к вершин, и рандомом свяжем каждую вершину с десятком других. После чего будем обходить граф вширину 1кк раз. Затем разрежем этот граф на графы, в каждом из которых будет по 10к вершин, ты ведь хотел продолжать работать с "частью вершин". Всю эту логику мы запихаем в функцию, которую будем вызывать вой
а сделайте плиз
хотя бы на с++
очнеь хочется посмотреть как щас на нем пишут
Из моего опыта работы, память начинает утекать в программах на языках с GC раньше и такие проблемы там встречаются чаще, чем на Си++, потому что новички всерьёз рассчитывают, что язык программирования спасёт их от всех бед.видимо у меня маленький опыт
ни разу не видел как память в джаве утекает...
PS. Не волнуйся, маленький опыт поддаётся увеличению!
утильзы для синтаксического сахара
package patternargs;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Mikhail Evdokimov
*/
public class PatternArgsUtils {
public static <T> T invokePatternArgs(Object obj, Object... args) throws Exception {
String methodName = (String) args[0];
Object[] patternArg;
if (args.length == 1) {
patternArg = new Object[0];
} else if (args.length == 2) {
patternArg = (Object[]) args[1];
} else {
throw new InternalError("Support for simple args in the beginning is not yet implemented");
}
// TODO check method for every i
if (patternArg.length == 0) {
Method m = obj.getClass.getMethod(methodName);
return (T) m.invoke(obj);
}
if (patternArg.length == 1) {
Method m = obj.getClass.getMethod(methodName, patternArg[0].getClass;
return (T) m.invoke(obj, patternArg[0]);
}
if (patternArg.length == 2) {
Method m = obj.getClass.getMethod(methodName, patternArg[0].getClass patternArg[0].getClass;
return (T) m.invoke(obj, patternArg[0], patternArg[1]);
}
Method m = obj.getClass.getMethod(methodName, patternArg[0].getClass
patternArg[0].getClass patternArg[0].getClass patternArg.getClass;
Object[] dest = (Object[]) Array.newInstance(patternArg[0].getClass patternArg.length - 3);
if (dest.length > 0) {
System.arraycopy(patternArg, 3, dest, 0, patternArg.length - 3);
}
return (T) m.invoke(obj, patternArg[0], patternArg[1], patternArg[2], dest);
}
public static <T> T[] arr(T x1, T x2, T[] xs) throws Exception {
List<T> l = new ArrayList<T>(2 + xs.length);
l.add(x1);
l.add(x2);
l.addAll(Arrays.asList(xs;
return l.toArrayT[]) Array.newInstance(x1.getClass 2 + xs.length;
}
}
вот решение той задачи
package test;
/**
* @author Mikhail Evdokimov
*/
public interface iAct {
Double act(Double... l) throws Exception;
}
package test;
import static patternargs.PatternArgsUtils.arr;
import static patternargs.PatternArgsUtils.invokePatternArgs;
/**
* @author Mikhail Evdokimov
*/
public class Act implements iAct {
public Double act {
return 0d;
}
public Double act(Double x) {
return x;
}
public Double act(Double x, Double y) {
return x * y;
}
public Double act(Double x, Double y, Double z, Double... xs) throws Exception {
return x + (x + y) * z + act(arr(y, z, xs;
}
@Override
public Double act(Double... l) throws Exception {
return invokePatternArgs(this, "act", l);
}
public static void main(String[] args) throws Exception {
iAct act = new Act;
System.out.println("act(2) = " + act.act(2d;
System.out.println("act(2,3) = " + act.act(2d, 3d;
System.out.println("act(2,3,4) = " + act.act(2d, 3d, 4d;
System.out.println("act(2,3,4,5) = " + act.act(2d, 3d, 4d, 5d;
System.out.println("act(2,3,4,5,6) = " + act.act(2d, 3d, 4d, 5d, 6d;
}
}
"C:\Program Files\Java\jdk1.6.0_06\bin\java" -Didea.launcher.port=7535 "-Didea.launcher.bin.path=C:\Program Files (x86)\JetBrains\IntelliJ IDEA 7.0\bin" -Dfile.encoding=windows-1251 -classpath "C:\Program Files\Java\jdk1.6.0_06\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.6.0_06\jre\lib\jce.jar;C:\Program Files\Java\jdk1.6.0_06\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.6.0_06\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.6.0_06\jre\lib\resources.jar;C:\Program Files\Java\jdk1.6.0_06\jre\lib\rt.jar;C:\Program Files\Java\jdk1.6.0_06\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.6.0_06\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.6.0_06\jre\lib\ext\sunjce_provider.jar;C:\prog\haskell\out\production\haskell;C:\Program Files (x86)\JetBrains\IntelliJ IDEA 7.0\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain test.Act
act(2) = 2.0
act(2,3) = 6.0
act(2,3,4) = 34.0
act(2,3,4,5) = 80.0
act(2,3,4,5,6) = 148.0
Process finished with exit code 0
Можно пример, когда указанные мной условия соблюдены и летит этот самый null pointer exception?Какие условия? Ты же тут втираешь, что C# спасает от любых условий. NULL pointer exception может породить код, в котором используется ссылка на класс, значение которой равно NULL. Если ты не писал кода сложнее трёх классов и длиннее 100 строк, то ты конечно этого не поймёшь.
Мне что-то ничего, что может его породить, в голову не приходит.
Сделаем реализацию графаТак что, ты согласен, что у тебя получится код, в котором будет так:
Ага, а ещё лучше - рассмотрим шарообразного коня в вакууме.
Потом мы убедимся, что время работы тупо написанной (а ты именно так предлагаешь делать граф) программы на C# просасывает программе на Си++. И ещё мы поймём, что C# отжирает памяти в десятки раз больше. Мне просто очень интересно, куда тогда денутся твои аргументы в пользу невзъебенной крутости C#?
Если не согласен, то напиши код. Мы посмотрим, какой ты умный, и как C# потянет 500к объектов, которые друг на друга ссылаются. Если ты не можешь написать конкретный код, тогда иди отсюда нафиг и помалкивай о плюсах и минусах языков программирования.
а сделайте плизКстати, решение в лоб будет проще и лучше всего работать на Java. (Только если ей давать максимальное количество памяти меньше или равное 256мб, странное поведение у JVM.)
хотя бы на с++
очнеь хочется посмотреть как щас на нем пишут
Все правильно, но его (С++) недостатки являются следстием его достоинств, связанных с устремлениями Стауструпа сделать язык, который ни в чем (!) не будет уступать С (в том числе по скорости и по универсальности и т.д.).
> 1. мелкие ошибки в C# или в том же Delphi менее критичны, чем в C++
все верно, в С++ очень легко допрустить нетривиальные ошибки, но вызвано это тем, что язык позволяет сделать одно и тоже десятком разных способов, различающихся мелкими нюансами, соотвественно, если говорить не о типовых случаях, то на нем можно сделать все, на что способна аппаратура
> 2. в C# и Дельфи есть нормальная поддержка бинарных либ.
да и поэтому в больших проектах на С++ вылезают разные ненужные сложности. Но это из-за желания Стауструпа развязать компиляторам руки и не фиксировать стандартом бинарного представления объектов (но мне лично кажется, что с этим он уже переборщил, особенно если учитывать его ратования за рынок плюсовых библиотек)
Поэтому если говорить о ,как я его называю, "попсовом программировании" (формочки, реализация всяких там "бизнес логик" и пр. то C#, конечно, удобнее. Но если есть жесткие требования к техническим характеристикам софта, то имхо без плюсов не обойтись. (все это мое имхо)
Сделаем реализацию графа: ты тупо на C# (ведь там же реализация в лоб рулит, как ты утверждаешь а я на Си++в чем интерес сравнивать решения лобовых задач?
интереснее смотреть на решения задача со сложной логикой.
в чем интерес сравнивать решения лобовых задач?Интерес в том, что пенарtoor2 давит на реализацию структуры хранения данных (иначе я не могу назвать граф из 10к+ эдементов) в лоб. Ты, конечно же, понимаешь, что в лоб на C#/Java такую задачу лучше не решать. А я просто хочу поставить засранца на место. Не будет кода - он окончательно докажет свою несостоятельность.
интереснее смотреть на решения задача со сложной логикой.
Ты, конечно же, понимаешь, что в лоб на C#/Java такую задачу лучше не решать. А я просто хочу поставить засранца на место.у меня есть решение - где на C# в лоб(т.е. без оптимизации структур хранения) обрабатывается граф из 10млн. объектов - прога жрет два гига, но работает стабильно.
есть решение на C++(которое пилят уже 4 года) - жрет меньше раза в 4, но раз в пару месяц при изменений условий эксплуатации она валится в корку, из-за провисшего где-нибудь указателя
зы
основные отличия от твоей задачи:
1. объекты в графе разнородные, связи тоже
2. время жизни каждого объекта или связи тоже рандомное
3. есть несколько потоков - которые этот граф меняют/читают
4. есть длинные событийные процессы, которые работают с этим графом
у меня есть решение - где на C# в лоб(т.е. без оптимизации структур хранения) обрабатывается граф из 10млн. объектов - прога жрет два гига, но работает стабильно.А меня есть сервис 24/7/365 на Си++, который не упал, не потёк и не повис ни разу после релиза и установки десяткам клиентов. (Многопоточный, обслуживает до десятков клиентов и несколько периферийных устройств параллельно.) Написал я его за 2 месяца, плюс неделя на каждое новое периферийное устройство. В то время, как GUI софт из того же проекта, сделанный на C#, пилят уже третий год и всё равно он продолжает приходить в неработоспособное состояние. И что теперь?
есть решение на C++(которое пилят уже 4 года) - жрет меньше раза в 4, но раз в пару месяц при изменений условий эксплуатации она валится в корку, из-за провисшего где-нибудь указателя
кстати как ты оформляешь кусок кода, который локально берет из графа объект по week_ptr и что-то с ним делает, при условии что твой кусок кода обязан вызывать какие-то внешние колбаки (например, с информацией о том, что ты объект обработал)?
А меня есть сервис 24/7/365 на Си++,разработчик один?
разработчик один?У фреймворка один, а поддержку периферии делали ещё человек пять. (Причём никто не убил фреймворк, он поддерживал транзакционность своего состояния и хорошо отделял свою логику от логики периферии.) У каждой GUI странички у нас был тоже один разработчик. Ни о чём это не говорит.
на реальном коде все проблемы решений - лучше видны.
То что все решает стоимость разработки. Кучка индусов + C# дешевле одного Гуру++.
пример кода давай на вышеуказанные условия.На какие условия, какого кода?
1. объекты в графе разнородные, связи тоже
2. время жизни каждого объекта или связи тоже рандомное
3. есть несколько потоков - которые этот граф меняют/читают
4. есть длинные событийные процессы, которые работают с этим графом
кстати как ты оформляешь кусок кода, который локально берет из графа объект по week_ptr и что-то с ним делает, при условии что твой кусок кода обязан вызывать какие-то внешние колбаки (например, с информацией о том, что ты объект обработал)?
чужие посты не читаешь что ли?Нет, так не пойдёт. Во-первых, у тебя уже есть готовое решение, и ты не будешь тратить время на работе на кодирование. Ставь задачу, которую ты напишешь обязательно в лоб и с нуля. Во-вторых, сначала мы подождём кода от пенортура2, чтобы так сказать сравнить код "дешёвых индусов" и понять, способен ли он на что-то кроме пиздежа.
аля
var item = graph.getItem(14);
Console.WriteLine("Обработан элемент: {0} у родителя '{1}'", item.Name, item.Parent.Name);
_OnProcessed(item);
Console.WriteLine("Элемент '{0}' у родителя '{1}' обработан и клиенты об этом оповещены",
item.Name, item.Parent.Name);
ps
добавил еще обращение к родителю
тебе тяжело написать три строчки?Хорошо:
node_ptr node = graph.get_node(14);
std::cout << "Обработан: " << node->get_name << " у родителя (которого в C# мы тоже не проверили на NULL) " <<
node->get_parent->get_name << std::endl;
on_processed(node);
std::cout << "Обработан: " << node->get_name << " и клиеты уведомлены" << std::endl;
логика node_ptr какая?
обращение к родителю добавь еще плиз (как у меня в коде после исправления хочу посмотреть как ты оформляешь именно доступ к week_ptr-ам.Код выглядит именно так, как я его написал. Ничего не могу поделать, здесь в общем-то не нужен доступ к weak_ptr. Про логику node_ptr я ещё не думал, но это shared_ptr<node>
логика node_ptr какая?
т.е. у node на parent тоже будет shared_ptr?
у родителя (которого в C# мы тоже не проверили на NULL)но у меня то будет exception который я перехвачу сверху, а у тебя core dumped
разницу чуешь?
std::cout << "Обработан: " << node->get_name << " и клиеты уведомлены" << std::endl;а здесь где доступ к родителю?
у родителя (которого в C# мы тоже не проверили на NULL)кстати не ленись давай,
свой кусок кода я лишь привел, как пример того, что я хочу видеть.
в нем я знаю кстати несколько сомнительных моментов.
мне интересно видеть именно тот код, который написал бы именно ты в реальном боевом приложении.
но у меня то будет exception который я перехвачу сверху, а у тебя core dumpedНет, у меня get_parent выкинет исключение.
разницу чуешь?
Нет, у меня get_parent выкинет исключениеесли нет родителя? на корневом элементе тоже?
свой кусок кода я лишь привел, как пример того, что я хочу видеть.Сомнительных моментов я могу придумать большое количество, особенно если учитывать, что ты упоминал про многопоточное чтение-запись графа.
в нем я знаю кстати несколько сомнительных моментов.
мне интересно видеть именно тот код, который написал бы именно ты в реальном боевом приложении.
Исходя из имеющихся данных, ровно этот код я бы написал в боевом приложении.
если нет родителя? на корневом элементе тоже?Тоже. У нас у обоих код в этом случае выкидывает исключение. Ты можешь придумывать задачи сколько угодно. Все они всё равно будут одинаковыми: либо реализация структуры данных типа граф (которая в бусте у нас уже есть либо агрегация.
хорошо пусть будет не родитель, а сосед слева тогда как?
там какой ptr будет? week_ptr, shared_ptr?
и этого соседа слева тоже хочется в onprocessed запихатьЕсли ты пихаешь куски графа в коллбэки, то на любом языке туда надо передать и сам граф. Особенно, если ты планируешь пихать это в несколько потоков. На любую удерживаемую вершину тебе будет нужен shared_ptr
там какой ptr будет? week_ptr, shared_ptr?
Ты можешь придумывать задачи сколько угодновот блин словоблудие развел, нет чтобы реальный код писать
так будет или как?
shared_ptr<node> node = graph.get_node(14);
week_ptr<node> left = node->get_left;
if (left == NULL)
return;
std::cout << "Обработан: " << node->get_name << " вместе с соседом " <<
left->get_name << std::endl;
on_processed(node, left);
std::cout << "Обработан: " << node->get_name << " вместе с соседом " <<
left->get_name<< " и клиеты уведомлены" << std::endl;
...
class node
{
week_ptr<node> left;
...
}
..
on_processed(shared_ptr<node>& node, shared_ptr<node>&left);
так будет или как?Не так. Я же не заставляю тебя отказываться от свойств? Как оно будет устроено внутри я не знаю. Я не спорю, что при решении в лоб строк на C# будет немного меньше. Или к чему все эти вопросы?
node_ptr left = node->get_left;
shared_ptr<node> node = graph.get_node(14);
week_ptr<node> left = node->get_left;
if (left == NULL)
return;
std::cout << "Обработан: " << node->get_name << " вместе с соседом " <<
left->get_name << std::endl;
on_processed(node, left);
std::cout << "Обработан: " << node->get_name << " вместе с соседом " <<
left->get_name<< " и клиеты уведомлены" << std::endl;
node_ptr node = graph.get_node(14);
node_ptr left = node->get_left;
std::cout << "Обработан: " << node->get_name << " вместе с соседом " <<
(left ? left->get_name : "NULL") << std::endl;
on_processed(node, left);
std::cout << "Обработан: " << node->get_name << " вместе с соседом " <<
(left ? left->get_name : "NULL") << " и клиеты уведомлены" << std::endl;
так в итоге и получается, что не понятно теперь когда этот самый node умрет...
так в итоге и получается, что не понятно теперь когда этот самый node умрет...Когда умрёт последний shared_ptr
На IA-32 - не оптимизируется. А у меня на AMD64 неплохо так оптимизируется.
Какие условия? Ты же тут втираешь, что C# спасает от любых условийНе от любых.
Похоже, что ты не читал мой пост.
Я там писал, что надо аккуратно вести себя в конструкторах и деструкторах. Не так уж и много, по сравнению с плюсами.
сначала мы подождём кода от пенортура2Какого кода?
Если ты про написать программу с огромнцым графом и без чего-либо ещё - уже и я, и сказали тебе, что это не представляет никакого интереса, и ни о чём не говорит.
Если же ты хочешь получить реальное приложение со сложной логикой... эти приложения "просто так не делают", а делают под конкретные задачи; и на них уходит куча времени, за пять минут тебе никто ничего не напишет (и ты за пять минут не напишешь аналог на C++).
Я там писал, что надо аккуратно вести себя в конструкторах и деструкторах. Не так уж и много, по сравнению с плюсами.По сравнению с чем в плюсах? Ты так ничего и не обосновал, кроме того, что ты абсолютно не знаешь языка.
Какого кода?Короче, всё ясно. Ты просто пиздобол. Я тебе, можно сказать, в руки сдал все козыри для того, чтобы ты мог обосновать хоть какие-то преимущества C#. Но ты, в силу своей ограниченности, зассал и никому ничего не доказал, кроме своей безграмотности.
Если ты про написать программу с огромнцым графом и без чего-либо ещё - уже и я, и сказали тебе, что это не представляет никакого интереса, и ни о чём не говорит.
Если же ты хочешь получить реальное приложение со сложной логикой... эти приложения "просто так не делают", а делают под конкретные задачи; и на них уходит куча времени, за пять минут тебе никто ничего не напишет (и ты за пять минут не напишешь аналог на C++).
PS Графы я сегодня реализовал на трёх языках. В любой реализации меньше 300 строк.
PPS Учи принципы проектирования софта, в правильном приложении со сложной логикой не бывает десятков тысяч объектов, которые друг на друга ссылаются.
Графы я сегодня реализовал на трёх языках. В любой реализации меньше 300 строкИ что? Какое отношение это имеет к реальным задачам?
в правильном приложении со сложной логикойПонятно, что для тебя - "сложная логика".
По сравнению с чем в плюсах?Открой мозг и включи глаза.
Да, в C# и Java тоже есть возможность получить Null pointer exception, как и в плюсах.
Чтобы этого не произошло в c#, надо аккуратно вести себя в конструкторах и деструкторах (впрочем, деструкторы, наверное, при наличии IDisposable нафиг не нужны).
Чтобы этого не произошло в плюсах, аккуратно надо себя вести везде. И думать ещё о куче других вещей.
И что? Какое отношение это имеет к реальным задачам?Самое прямое. Ты не можешь привети даже банальный практический пример кода на языке, от которого ты тут так писаешь кипятком. Этот раздел называется Development, и здесь привыкли совмещать теорию и практику. Пока ты не готов к практике и теоретизируешь, причём не имея понятия о предмете своих теорий, тебе здесь делать нечего.
Понятно, что для тебя - "сложная логика".
Да, для меня сложная логика - это именно сложная логика. А не код в формате спагетти, построенный по архитектуре "бабушкин клубок", что ты явно подразумеваешь под невзъебенной сложностью.
Открой мозг и включи глаза.Подтверди это примером кода на 5-10 строк? При чём меня интересуют следующие вопросы. Во-первых, почему файналайзеры (деструкторы) при наличии IDisposable нафиг не нужны? Во-вторых, почему в следующем коде, где я очень аккуратно веду себя в конструкторе, вылетает null pointer?
Да, в C# и Java тоже есть возможность получить Null pointer exception, как и в плюсах.
Чтобы этого не произошло в c#, надо аккуратно вести себя в конструкторах и деструкторах (впрочем, деструкторы, наверное, при наличии IDisposable нафиг не нужны).
Чтобы этого не произошло в плюсах, аккуратно надо себя вести везде. И думать ещё о куче других вещей.
class CSharpClassWithVeryCarefulConstructor
{
public void func {}
}
...
static void someFunction
{
CSharpClassWithVeryCarefulConstructor c = null;
c.func;
}
Ты не можешь привети даже банальный практический пример кода на языке, от которого ты тут так писаешь кипяткомПример графа - могу. Просто влом, и непонятно, зачем.
Пример графа - могу. Просто влом, и непонятно, зачем.Ну тогда приведи пример не графа, а чего-то другого и покороче. Но только такого, чтобы реализация на Си++ требовала того, на что ты изначально наехал: ручного вызова delete.
к сожалению, в тех реальных приложениях, которые я встречал - все эти подводные камни избегались через раз и приводили к падениям.
да, в C# все было тоже самое - то бывает хороших код, который обходит подводные камни, бывает - плохой, но в C# это не приводило к падениям.
ps
но в твоем примере осталась еще одна проблема, что будет если один и тот же объект будет два раза добавлен в граф (второй раз неявно, как один из внуков самого себя)?
да, основные подводные камни ты избежал.
Кроме скорости работы. (Ае, взял пенartoorчега2 на понт.) При реализации в лоб GC, конечно же, рулит подсчёт ссылок, если объекты очень маленькие. Это было не очевидно только для peenortoor2. (При увеличении размера объекта C# отжирает до 1гб и работает в десятки раз медленнее только из-за того, что свопится.) Завтра проведу дополнительные тесты. Пока что всех порвала Java , только ей нельзя ставить xmx больше 256mb. Надеюсь, что они исправят эти странные проблемы с JVM. Кроме того, мне интересно проверить реализацию std:: tr1 ::shared_ptr от MS.
да, в C# все было тоже самое - то бывает хороших код, который обходит подводные камни, бывает - плохой, но в C# это не приводило к падениям.У меня есть замечательный класс, который ипользуется уже в четвёртом коммерческом проекте. Он умеет сохранять дампы падения и намеренно ронять программу. Маст хэв для всех Си++ программ, жалко, что я не знаю, как убить .NET приложение с сохранением дампа. Помогло бы находить дедлоки.
но в твоем примере осталась еще одна проблема, что будет если один и тот же объект будет два раза добавлен в граф (второй раз неявно, как один из внуков самого себя)?
Граф строится на слабых ссылках, поэтому этой проблемы не возникает. Возникает другая проблема: нельзя начать граф от любой вершины, если ты удалил структуру хранения данных. Останется только эта вершина. Конечно, я мог бы решить и эту проблему с помощью смарт поинтеров, только в лом было.
Маст хэв для всех Си++ программ, жалко, что я не знаю, как убить .NET приложение с сохранением дампа. Помогло бы находить дедлоки.запускаешь windbg - и это он тебе по .net-у все без всякого убития выдаст.
запускаешь windbg - и это он тебе по .net-у все без всякого убития выдаст.Ты его запускаешь у клиентов? Если локально, то и по Си++ тебе всё выдаст. Так мы можем сделать дампы, которые нам отсылают по инету.
Надо заходить в раздел почаще...
Охуенный тред, много интересного узнал. Ну и поржал конечно. Всем спасибо.Всегда пожалуйста.
Девелопмент вообще уникальный раздел: +- ставят от балды и без оснований, типа нефиг тут; кода мало пишут, чтобы не заклевали; ну и, естественно, заклёвывают тех, кто пытается запостить код. И ещё тут водятся отборные ооебаны типа кохтпы и пенартоора, и психи типа меня.
Так мы можем сделать дампы, которые нам отсылают по инету.а чо, в венде для этого уже нельзя без особых классов?
зы вчера на работе как раз скрипт накатал, который бектрейсы от корок шлёт на почту заинтересованным лицам.
а чо, в венде для этого уже нельзя без особых классов?Понимаешь, мы не катаем скрипты, чтобы отправить core клиентам. (Кстати, что вы делаете, если лимит на коре нулевой?) Мы устанавливаем программу методом "one click", и она потом автономно работает.
зы вчера на работе как раз скрипт накатал, который бектрейсы от корок шлёт на почту заинтересованным лицам.
И вообще вместо того, чтобы начинать холи вар, лучше бы пофиксил adept. Он всё время падает в кору. А автор, видимо школьник, кто ещё будет программировать забесплатно, не фиксит в нём баги. Хотя я честно отправлял кору раз десять, наверное.
(Кстати, что вы делаете, если лимит на коре нулевой?)мы пишем для себя, поэтому не нулевой, приложения 365/7/24 валящиеся раз в сутки, и нас не ебут проблемы пионеров с вендой и next-next-next - нам бы со своими разобраться
И вообще вместо того, чтобы начинать холи вар, лучше бы пофиксил adept.
начнём другой и продолжим старый: кде говно, потому что написано на C++
начнём другой и продолжим старый: кде говно, потому что написано на C++Так у тебя проблемы с Си++ или с вендой?
на венду мне посрать: сама сдохнет. У меня проблемы именно с цепепе. Я даже скажу почему - у него нет нормальной стандартной библиотеки. Чтобы строчку по-человечески поделить на разделителях, нужно свою хуйню бабахать. То, что есть в бусте - полное говно и плод воображения любителя грибов. А оставшиеся сторонние библиотеки - тоже говно (копирайт ты).
Чтобы строчку по-человечески поделить на разделителях, нужно свою хуйню бабахать. То, что есть в бусте - полное говно и плод воображения любителя грибов.Да, в бусте не всё удобно.
Что касается библиотеки, то в Си++ нету так же SMTP (есть в .NET сокетов (.NET, Java POP3 (почему-то нету в .NET!?) и много чего ещё. Дело в том, что C# тесно связан с платформой .NET, а Си++ это скорее язык програмирования. Если ты заметил, то мы здесь не обсуждаем RAD или приверженцев одного языка программирования, или платформы для разработки ПО. Кстати, на C# я сделал больше коммерческих проектов, чем на Си++.
PS А венда не сдохнет.
Чтобы строчку по-человечески поделить на разделителях, нужно свою хуйню бабахать.Ну это всё-таки необязательно.
std::vector<std::string> tokens;
std::string source("blabla,blablabla,zomg,v rot mne nogi,v glaz pechen'e");
boost::split(tokens, source, boost::is_any_of(",";
Пиздец говно эти ваши плюсыя даже не разобравшись о чём ты, рекомендую мелкими сцыкливыми шажками идти нахуй
Оставить комментарий
kruzer25
Пиздец говно эти ваши плюсы.Когда же разработчику думать о содержательной части, если всё своё время он будет тратить на работу с памятью?