В штатах не просто «можно», там на вас, скорее всего, очень странно посмотрят, если вы предьявите паспорт вместо водительсткого или state ID. Паспорта по сути есть только у тех, кому надо ездить за рубеж, и используются только как загран, а не внутри страны (хотя это и возможно).
>> Вы полагаете, что в каком-нибудь потоке будет ссылка на не до конца проинициализированный экземпляр целевого класса?
Модель памяти JVM позволяет подобное — т.е. сначала выделить память под объект, потом присвоить указатель на нее в поле, и только потом вызвать конструктор. Именно поэтому даже для double checked locking нужен volatile (причем с семантикой Java 5+).
А зачем иметь дом именно в Редмонде? Да, там (а также Белвью и Киркланд) — дорого. Но уже в Саммамише заметно дешевле, при том, что оттуда вполне можно добираться до работы (в Редмонде) за 20-25 минут. А можно забраться и дальше, в Снокволми, например — оттуда 30-40 минут по I-90, вполне терпимо.
Аренда, насколько мне известно, такая дорогая только вблизи кампуса, дальше все лучше. Я снимаю квартиру в южном Белвью в хорошем (и дорогом) районе, две спальни + гараж — $1800. 17 минут до работы.
>> не видел чтобы дети играли на улице до темна. И вообще понятие улицы тут нет. Есть свои дворы, там гуляй сколько хочешь, но на улице просто нечего делать, там ездят машины. Все парки обычно работают до темноты, потом закрываются. В парках обычно запрещен алкоголь и публика обычно приличная. Вероятность того что пристанут в духе «э, дай позвонить» в этих местах равна нулю. Но чтобы в парк попасть надо ехать на машине, пешком туда не дойдешь, так что «отпустить» детей не получится, их туда надо отвезти.
Не соглашусь — это все тоже сильно зависит от места. В моих краях (Bellevue) по улицам вполне можно ходить, и ходят. Парки есть вблизи — один непосредственно рядом с домом, три минуты ходьбы, при этом это полноценный парк, довольно-таки большой. Второй парк минутах в десяти, но это Cougar Mountain wildland park, т.е. по сути просто большой кусок леса на горе с аккуратными тропинками в нем. Оба теоретически закрываются после темноты, но на практике я никогда не видел там запертые ворота, даже в два часа ночи.
Сиэттл с окрестностями ближе. Хороший дом вполне реально найти за 400-500 (можно и дешевле, если жить подальше — при этом все равно вписываясь в commute <= 40 минут), MS/Amazon/Google, ну и по мелочи полно всего :)
>> Громкую музыку очень хорошо слышно из соседнего дома обычно. Даже разговоры частенько слышно.
Ну дык, это смотря какой дом. В идеале к нему неплохо бы еще пару акров земли :)
>> В особо престижных районах, кстати, бывает так, что изменение внешнего вида своего двора надо согласовывать с соседями-снобами.
Не знаю, на сколько это распространено, но такое бывает.
Это т.н. HOA (Home-owner association). Распространено достаточно, но вполне реально найти дом без подобных заморочек, особенно если смотреть подальше от города.
>> Тут вы не правы (если мы говорим про Java) — close всего лишь закрывает длительную операцию. Т.е. фактически освобождается какой-то занятый ресурс, но не уничтожается сам объект (что для деструктора является обязательным условием).
Это вопрос терминологии — само слово «деструктор» четко не определено. Например, в C# им зачем-то назвали finalizer, который вообще ни разу не детерминистичный. Я его использовал в смысле «обратная сторона инициализации, которая обеспечивает все гарантии в RAII».
Объект действительно не уничтожается ни в Java, ни в C#, но он, как правило, переходит в состояние «невозможно использовать», когда все методы кидают исключения — причем в большинстве случаев это one-way ticket, т.е. вернуть его обратно в нормальное состояние невозможно. В C# это вообще прописано в контракте Dispose. С моей т.з, важное в деструкторе то, что он освобождает все ресурсы, требующие детерминистичного высвобождения (в данном языке). Соответственно, в плюсах это включает в себя и память, а в Java и C# — нет, поэтому и есть эта разница со временем жизни. Но на практике для RAII она совершенно не важна.
>> Вопрос с деревом решается как и в деструкторе (хотя мне не очень понятна область применения дерева относительно ресурсов) — каждый объект закрывает дочерние объекты и закрывается сам.
С деструкторами каждый объект не должен явно закрывать дочерние объекты, его деструктор автоматически позовет их деструкторы. Более того, такой деструктор вообще не надо определять (если у объекта нет своей логики освобождения ресурсов) — он сам появится автоматически при наличии полей, которые надо чистить. Это принципиальная разница с close(), который надо будет руками определять, и руками же звать на всех владеемых объектах.
Дерево с ресурсами — ситуация вполне типичная. Например, в UI-фреймворках, дерево обычно соответствует дереву виджетов, а их ресурсы — это оконные хэндлы (т.е. HWND на Win32, например). И при убивании корня дерева (обычно, окна верхнего уровня), нужно освободить вот это все.
Еще часто бывает ситуация, когда сам по себе граф объектов не представляет ресурсы, но у каждого объекта во владении есть еще один или несколько несвязанных объектов, которые надо прибить — например, по файлу на нос. Соответственно, у объектов в дереве нужен деструктор, просто для того, чтобы он позвал таковой на файле. Вообще, деструкторы — заразная штука, в прямом смысле :)
>> IDisposable и AutoClosable всё-таки разные (совсем) вещи. Все объекты в Java имеют метод dispose. Но есть причины по которым его не используют — JVM не гарантирует время вызова этого объекта.
Вы, кажется, путаете здесь dispose (которого в Java таки нет — точнее есть, но только у отдельных классов, например в AWT), и finalize (который есть и в C#, и в Java у всех объектов, но в C# для него используется особый синтаксис, хотя на уровне CLR там все равно Finalize). IDisposable — это именно самый что ни на есть прямой эквивалент AutoClosable, интерфейс и метод для детерминистичного высвобождения ресурсов, в сочетании с конструкцией языка для автоматического вызова этого метода.
Как убивается объект-владелец, как раз не важно. Пусть даже это будет выход из блока. Но как он будет в свою очередь автоматически убивать то, чем владеет?
shared_ptr соорудить как раз вполне можно, но там будут ровно те же ограничения — если у вас есть только «using», то все ваши shared_ptr'ы должны будут быть локальными в каком-то блоке, или же на них придется где-то явно вызывать release.
В деструкторе владельца не нужно явно вызывать деструкторы дочерних объектов.
А тип поля (если забыть про прочий профит от типизации) прописывается не ради деструктора, а ради конструктора — т.е. указывает на то, объект какого вообще типа мы создаем. Этого вы не избежите и в языке с динамической типизацией. А автоматический вызов деструктора там прилагается бесплатно, в отличие от.
>> (2ой абзац) Посмотрите на AutoClosable интерфейс. Все необходимые операции завершаются вполне детерминистично. Аналог вторичного функционала деструкторов. Или для вас деструкторы — менее ручное, чем такое архитектурное решение?
Нет, это вполне нормально. Но, собственно, AutoClosable::close — это и есть деструктор. :)
С одним «но». Попробуйте на нем реализовать ситуацию, когда у вас не один объект, а дерево. Корень-то вы высвободите через AutoClosable автоматически, ок. А вот все «висящие» на нем объекты придется освобождать ручками в его close(). И так для каждого уровня дерева. Профит семантики плюсовых деструкторов в том, что они работают для всего, а не только для локальных переменных, причем автоматически — объявили переменную, получите вызов деструктора.
Кстати, вы, наверное, в курсе, что в C# аналогичная AutoClosable вещь называется IDisposable (и метод, соответственно, Dispose). Так вот там, C++/CLI отображает деструкторы ref-классов на Dispose в генерируемом коде. Но они сделали правильно, и оставили у них полную семантику плюсовых деструкторов — т.е. если в одном ref class есть поле типа другого ref class, и второй класс имеет деструктор (т.е. на уровне CLI — реализует IDisposable), то первый тоже автоматически получает IDisposable, который вызовет Dispose на дочерний объект.
>> Абсолютный аналог — даты. Вот есть java.lang.Date, который содержит UnixTimeStamp, а есть Calendar и его субклассы типа GregorianCalendar и прочих, которые умеют UTS переводить в дату на выбранном календаре. Это в общих чертах. Это и является архитектурным решением.
Это ничем не отличается от решения с шаблонами, кроме того, что вы напишете больше кода руками. Т.е. с вашим подходом вы вручную будете определять классы типа SiLength, SiTime и SiVelocity, и вручную же описывать, что SiLength/SiTime дает SiVelocity. А потом отдельно делать то же самое для ImperialLength etc, и опять же руками описывать преобразования. В Boost.Unit типа «скорость» как такового нет, это составной шаблонный тип из расстояния и времени, что отражает его единицу измерения (м/с) — ни одной строчки кода специально для него писать не надо было. Аналогично, из скорости при делении на время точно так же автоматически получается ускорение, и т.д. А для разных систем, достаточно задать преобразование между базовыми единицами данной величины один раз, и все производные также получают их автоматически. Т.е. если вы умеете переводить футы в метры, то это автоматически будет применимо к переводу из фт/с в м/с.
Собственно, шаблоны вообще — это штука, абсолютно перпендикулярная тому, что вы назвали архитектурой. Они просто позволяют описывать куда более сложные решения с меньшим объемом кода.
>> Первоочерёдная задача деструктора — корректное закрытие объекта (потоков). С этим gc + обвязка вполне справляются.
Не справляется с этим GC. С памятью — да, но большинство других ресурсов (мьютексы, сокеты, хэндлы памяти etc) должны быть освобождены детерминистично, и GC здесь не помощник. Или под этим вы имеете в виду…
>> Вторичная — корректное «завершение» работы объекта может быть легко выполнено архитектурно — не вижу проблем с этой стороны.
В таком случае, объясните, как именно это «легко выполняется архитектурно» без ручного управления временем жизни в отсутствие деструкторов (и, как следствие, RAII).
>> Окей, шаблоны из гуд (хотя того же можно достичь, опять же, архитектурно)
Опять эта же непонятная фраза. Поясните на конкретном коде.
>> К тому же, как я уже говорил — там скорее архитектурная проблема (никто и не подумал, что масса / скорость может измеряться в других системах счисления).
Это именно та самая проблема, которая решается достаточной типизацией. Собственно, люди её решают так же, когда пишут единицы измерения после всех величин при рассчетах.
Вы имеете в виду аналог using в C#, который принимает функцию-параметр в качестве «тела»? Ну, для начала, это не эквивалент уже хотя бы потому, что в нем нельзя сделать return из внешней функции, или break из внешнего цикла. Но даже если забыть про это, каким образом это поможет вам в случае графа объектов, где при уничтожении владельца должны автоматически уничтожаться и все зависимые объекты?
Модель памяти JVM позволяет подобное — т.е. сначала выделить память под объект, потом присвоить указатель на нее в поле, и только потом вызвать конструктор. Именно поэтому даже для double checked locking нужен volatile (причем с семантикой Java 5+).
Аренда, насколько мне известно, такая дорогая только вблизи кампуса, дальше все лучше. Я снимаю квартиру в южном Белвью в хорошем (и дорогом) районе, две спальни + гараж — $1800. 17 минут до работы.
Не соглашусь — это все тоже сильно зависит от места. В моих краях (Bellevue) по улицам вполне можно ходить, и ходят. Парки есть вблизи — один непосредственно рядом с домом, три минуты ходьбы, при этом это полноценный парк, довольно-таки большой. Второй парк минутах в десяти, но это Cougar Mountain wildland park, т.е. по сути просто большой кусок леса на горе с аккуратными тропинками в нем. Оба теоретически закрываются после темноты, но на практике я никогда не видел там запертые ворота, даже в два часа ночи.
И, да, штат не собирает налог на доход.
Ну дык, это смотря какой дом. В идеале к нему неплохо бы еще пару акров земли :)
>> В особо престижных районах, кстати, бывает так, что изменение внешнего вида своего двора надо согласовывать с соседями-снобами.
Не знаю, на сколько это распространено, но такое бывает.
Это т.н. HOA (Home-owner association). Распространено достаточно, но вполне реально найти дом без подобных заморочек, особенно если смотреть подальше от города.
Это вопрос терминологии — само слово «деструктор» четко не определено. Например, в C# им зачем-то назвали finalizer, который вообще ни разу не детерминистичный. Я его использовал в смысле «обратная сторона инициализации, которая обеспечивает все гарантии в RAII».
Объект действительно не уничтожается ни в Java, ни в C#, но он, как правило, переходит в состояние «невозможно использовать», когда все методы кидают исключения — причем в большинстве случаев это one-way ticket, т.е. вернуть его обратно в нормальное состояние невозможно. В C# это вообще прописано в контракте Dispose. С моей т.з, важное в деструкторе то, что он освобождает все ресурсы, требующие детерминистичного высвобождения (в данном языке). Соответственно, в плюсах это включает в себя и память, а в Java и C# — нет, поэтому и есть эта разница со временем жизни. Но на практике для RAII она совершенно не важна.
>> Вопрос с деревом решается как и в деструкторе (хотя мне не очень понятна область применения дерева относительно ресурсов) — каждый объект закрывает дочерние объекты и закрывается сам.
С деструкторами каждый объект не должен явно закрывать дочерние объекты, его деструктор автоматически позовет их деструкторы. Более того, такой деструктор вообще не надо определять (если у объекта нет своей логики освобождения ресурсов) — он сам появится автоматически при наличии полей, которые надо чистить. Это принципиальная разница с close(), который надо будет руками определять, и руками же звать на всех владеемых объектах.
Дерево с ресурсами — ситуация вполне типичная. Например, в UI-фреймворках, дерево обычно соответствует дереву виджетов, а их ресурсы — это оконные хэндлы (т.е. HWND на Win32, например). И при убивании корня дерева (обычно, окна верхнего уровня), нужно освободить вот это все.
Еще часто бывает ситуация, когда сам по себе граф объектов не представляет ресурсы, но у каждого объекта во владении есть еще один или несколько несвязанных объектов, которые надо прибить — например, по файлу на нос. Соответственно, у объектов в дереве нужен деструктор, просто для того, чтобы он позвал таковой на файле. Вообще, деструкторы — заразная штука, в прямом смысле :)
>> IDisposable и AutoClosable всё-таки разные (совсем) вещи. Все объекты в Java имеют метод dispose. Но есть причины по которым его не используют — JVM не гарантирует время вызова этого объекта.
Вы, кажется, путаете здесь dispose (которого в Java таки нет — точнее есть, но только у отдельных классов, например в AWT), и finalize (который есть и в C#, и в Java у всех объектов, но в C# для него используется особый синтаксис, хотя на уровне CLR там все равно Finalize). IDisposable — это именно самый что ни на есть прямой эквивалент AutoClosable, интерфейс и метод для детерминистичного высвобождения ресурсов, в сочетании с конструкцией языка для автоматического вызова этого метода.
shared_ptr соорудить как раз вполне можно, но там будут ровно те же ограничения — если у вас есть только «using», то все ваши shared_ptr'ы должны будут быть локальными в каком-то блоке, или же на них придется где-то явно вызывать release.
А тип поля (если забыть про прочий профит от типизации) прописывается не ради деструктора, а ради конструктора — т.е. указывает на то, объект какого вообще типа мы создаем. Этого вы не избежите и в языке с динамической типизацией. А автоматический вызов деструктора там прилагается бесплатно, в отличие от.
Нет, это вполне нормально. Но, собственно, AutoClosable::close — это и есть деструктор. :)
С одним «но». Попробуйте на нем реализовать ситуацию, когда у вас не один объект, а дерево. Корень-то вы высвободите через AutoClosable автоматически, ок. А вот все «висящие» на нем объекты придется освобождать ручками в его close(). И так для каждого уровня дерева. Профит семантики плюсовых деструкторов в том, что они работают для всего, а не только для локальных переменных, причем автоматически — объявили переменную, получите вызов деструктора.
Кстати, вы, наверное, в курсе, что в C# аналогичная AutoClosable вещь называется IDisposable (и метод, соответственно, Dispose). Так вот там, C++/CLI отображает деструкторы ref-классов на Dispose в генерируемом коде. Но они сделали правильно, и оставили у них полную семантику плюсовых деструкторов — т.е. если в одном ref class есть поле типа другого ref class, и второй класс имеет деструктор (т.е. на уровне CLI — реализует IDisposable), то первый тоже автоматически получает IDisposable, который вызовет Dispose на дочерний объект.
>> Абсолютный аналог — даты. Вот есть java.lang.Date, который содержит UnixTimeStamp, а есть Calendar и его субклассы типа GregorianCalendar и прочих, которые умеют UTS переводить в дату на выбранном календаре. Это в общих чертах. Это и является архитектурным решением.
Это ничем не отличается от решения с шаблонами, кроме того, что вы напишете больше кода руками. Т.е. с вашим подходом вы вручную будете определять классы типа SiLength, SiTime и SiVelocity, и вручную же описывать, что SiLength/SiTime дает SiVelocity. А потом отдельно делать то же самое для ImperialLength etc, и опять же руками описывать преобразования. В Boost.Unit типа «скорость» как такового нет, это составной шаблонный тип из расстояния и времени, что отражает его единицу измерения (м/с) — ни одной строчки кода специально для него писать не надо было. Аналогично, из скорости при делении на время точно так же автоматически получается ускорение, и т.д. А для разных систем, достаточно задать преобразование между базовыми единицами данной величины один раз, и все производные также получают их автоматически. Т.е. если вы умеете переводить футы в метры, то это автоматически будет применимо к переводу из фт/с в м/с.
Собственно, шаблоны вообще — это штука, абсолютно перпендикулярная тому, что вы назвали архитектурой. Они просто позволяют описывать куда более сложные решения с меньшим объемом кода.
Не справляется с этим GC. С памятью — да, но большинство других ресурсов (мьютексы, сокеты, хэндлы памяти etc) должны быть освобождены детерминистично, и GC здесь не помощник. Или под этим вы имеете в виду…
>> Вторичная — корректное «завершение» работы объекта может быть легко выполнено архитектурно — не вижу проблем с этой стороны.
В таком случае, объясните, как именно это «легко выполняется архитектурно» без ручного управления временем жизни в отсутствие деструкторов (и, как следствие, RAII).
>> Окей, шаблоны из гуд (хотя того же можно достичь, опять же, архитектурно)
Опять эта же непонятная фраза. Поясните на конкретном коде.
>> К тому же, как я уже говорил — там скорее архитектурная проблема (никто и не подумал, что масса / скорость может измеряться в других системах счисления).
Это именно та самая проблема, которая решается достаточной типизацией. Собственно, люди её решают так же, когда пишут единицы измерения после всех величин при рассчетах.