LINUX.ORG.RU

Я хотел бы примкнуть к разработке какого нить c++ проекта..


0

0

Раньше писал на дельфе, щас под линухом выучил c++ но имею только теорию и маленькую чать практики... хотел бы присоединиться к разработке какого нить сравнительно молодого проекта на c++ желательно, хотя и си могу подучить... но желательно cpp... всё связанное только с линухом и никсами, винды для меня нет уже как 1.5 года... Здесь есть представители таких проектов? Помогу в разработке да и опыта наберусь... может чё хорошее получится :)


в 2.2 в реализации printk использвался vsprintf,
вместо vsnprintf,

в 2.4 это наконец-то поравили.

и если ты Die-Hard чего-то не знаешь то лучше промолчать,
а не демонстрировать свою некомпетенцию

anonymous
()
Ответ на: комментарий от anonymous

anonymous (*) (27.02.2005 0:16:21):

> а об атаках переполнением буфера ты слышал?

Конечно, слышал.

А ты мое сообщение читал?

Die-Hard ★★★★★
()
Ответ на: комментарий от anonymous

2anonymous (*) (27.02.2005 0:22:52):

> и если ты Die-Hard чего-то не знаешь то лучше промолчать, а не демонстрировать свою некомпетенцию

Так и знал, пионеры налетят...

Ну если нечего сказать, зачем флейм-то разводить?

Ну попробуйте отвлечься от того, что вы вычитали в книжках, написанных такими же "гениями".

Пример полезности snprintf в студию!

(допускаю, можно накопать пару. Сам не сталкивался).

Die-Hard ★★★★★
()
Ответ на: комментарий от anonymous

anonymous (*) (27.02.2005 0:07:52):

> годишные или двух годишные бенчмарки показывали что stdio быстрее iostream

Нет.

ЦеПП делает "пред-" форматирование в компилертайме. Поэтому оно быстрее.

Бенчмарки тут неоднократно обсуждались.

А, вообще, речь шла о том, что нельзя мешать в кучу два языка; о скорости речи вообще не было. Разумеется (для меня), программы на Си быстрее плюсатых (сейчас пионэры с другого фланга полезут! ;)

Die-Hard ★★★★★
()

Ладно, анонимусы, мне есть чем занятся поинтереснее, чем с детьми препираться. Не взыщите, я вам не учитель информатики. Глупости я проигнорирую, а школьные вопросы в десятый раз разжевывать не собираюсь.

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

На RSDN были долгие споры stdio vs iostream. Насколько я помню, stdio все же выигрывал. Чем кончилось - не помню. Возможно, iostream-ы все-таки победили :)

WFrag ★★★★
()
Ответ на: комментарий от Die-Hard

>Главное -- все таки, это Це или ЦеПП? На вид -- чисто Цешный код, зачем-то разбавленный ЦеППшными конструкциями.

Что-то не по глазам, где там C++?

WFrag ★★★★
()
Ответ на: комментарий от Die-Hard

>Пример полезности snprintf в студию!

ну детский сад на прогулке:

в милионнах програм создается буфер в стеке в текущей функции
типа

char buf[1024];

а потом делается sprintf(buf

можно застраховаться и написать

snprintf(buf, sizeof(buf)

и не надо при этом извращаться выделяя память и подсчитывая
сколько же максимально может весить результат форматирования

anonymous
()
Ответ на: комментарий от anonymous

>буфер в куче, в стеке только указатель на него

дизасемблируй и посмотри, в стеке все.

anonymous
()
Ответ на: комментарий от WFrag

2WFrag (27.02.2005 8:21:23):

> ...Насколько я помню, stdio все же выигрывал.

Он выигрывает (и то не всегда) на простом форматировании типа

printf("Hellow,%s!\n","veryVeryWhery....LongName");

Безусловно выигрывает, если надо не только форматировать динамически, но и формировать шаблон.

Если надо вывести сложноформатированный текст с кучей параметров, плюсатые механизмы вне конкуренции: оптимизированный код для форматирования формируется во время компиляции, не надо тратиться на разбор шаблонов и вызовы функций.

Конечно, для каждого конкретного случая можно написать на чистых Сях свою функцию, которая будет делать это быстрее.

Только все это -- типичные пузомерки. В подавляющем большинстве случаев разница (даже в разы) в скорости форматирования вывода пренебрежима. Просто надо помнить, например, что функция sprintf() не оптимальна для преобразования long -> char*.

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

Насколько я помню, там тестировали вообще read/write :)

Единственное, кто мог порулить - это STLPort со своей реализацией буффера через mmap (правда, только на чтение, ЕМНИП).

WFrag ★★★★
()
Ответ на: комментарий от WFrag

WFrag:

> где там C++?

Да, верно -- теперь это Це (C99). Все время забываю про этот стандарт. Так что основное замечание снимается :-)

Только зачем было так делать? Думаю, 99% компиляторов, установленных сегодня на компьютерах, не поймут такого Це.

Например, неделю назад доставленный компьютер, с предустановленной Красной Шапкой, gcc (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-34) -- ругается на for(int i=0; i<2;i++).

Die-Hard ★★★★★
()

sprintf vs. snprintf

Судя по вскипевшим страстям, вопрос, видимо, актуален. Позволю себе высказаться развернуто:

Почему _я_ считаю, что snprintf не полезна (и. более того, вредна). (Замечу, я имею в виду именно snprintf, к vsnprintf это (почти все) не относится).

1. Она появилась в C99, стандарте, который пока имеет проблемы. Эта же функция имеется в других стандартах, с немного другой семантикой. В старых (но все еще живых) Линуксах (libc4) ее нет, но есть алиас с игнорированием (!) аргумента size. Даже в glibc до 2.0.6 поведение этой функции отличается от C99!

2. Возбуждение страстей вокруг переполнения буфера связано с похожестью ситуации на случай с gets() vs. fgets(...,stdin), где длина принимаемого текста не известна заранее. Однако, в случае sprintf вся информация доступна процессу. Ограничение же размера буфера само по себе не устраняет опасность его переполненения автоматически: программист может подставить неверное ограничение, может вообще забыть (пере)распределить память и т.п. С другой стороны, в большинстве случаев размер формируемой строки заведомо меньше размера буфера, например, char buf[128]; sprintf(buf,"code %c = %d",'a','a'); Каков глубинный смысл использования тут snprintf()?

3. При применении snprintf все равно придется анализировать, был ли отрезан хвост (если нет -- то нужна ли вам формируемая строка вообще?) и принимать меры, если это случилось. Почему бы не сделать анализ один раз, вместо того, чтобы делать это дважды? К тому же, если вы по ошибке засунете в snprintf 3-гигабайтную строку, она аккуратно ее долопатит до конца -- ждите! (кстати, что она при этом вернет, одному Богу известно -- она же int возвращает, а не size_t!).

4. Как и всякая автоматизация "для чайников", эта функция провоцирует написание кривых программ: кажущееся отсутствие необходимости задумываться над проблемой возможного переполнения приводит к массовым "детскими ошибкам в алгоритмах.

Die-Hard ★★★★★
()
Ответ на: sprintf vs. snprintf от Die-Hard

>2.
>4.

аргумент в переводе на русский: "а если слоны бы летали".

если программист, не так ее будет использовать и т.д. это детский лепет.

>3.

зачем анализировать, если не ватило места чаще всего не вызывают еще
раз а просто выходят.

snprintf - просто предупреждает переполнение буфера в случаях

типа

char cmdline[1024];
snpinrtf(cmdline, sizeof(cmdline), "wavplay %s", filename);

anonymous
()
Ответ на: комментарий от anonymous

2anonymous (*) (27.02.2005 22:11:31):

Ты, извиняюсь, даже на родном пока языке толком изъясняться не научился. Зачем тебе Це? Попробуй Бэйсик, он тебе легче покажется ;)

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

>Ты, извиняюсь, даже на родном пока языке толком изъясняться не научился. Зачем >тебе Це? Попробуй Бэйсик, он тебе легче покажется ;)

подойди к зеркалу и скажи ему тоже самое,

у тебя же с логикой огромные проблемы,

аргумент типа а вот если программисты будут не те параметры
передавать snprintf, то будет хреново,
поэтому snprintf не нужно использовать
меня убил.

может все-таки используешь серое вещество,
вместо своей пятой точки, когда будешь писать?

anonymous
()
Ответ на: комментарий от anonymous

anonymous (*) (28.02.2005 0:14:27):

> у тебя же с логикой огромные проблемы,

Где?

> аргумент типа а вот если программисты будут не те параметры передавать snprintf, то будет хреново, поэтому snprintf не нужно использовать меня убил.

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

Попробую еще раз:

Страсти вокруг snprintf разгорелись потому в частности, что в мануале написано, что для избежания ошибок переполнения буфера следует использовать эту функцию вместо sprintf. Я замечаю, что само по себе наличие проверки на длину записи в функции не гарантирует от переполнения буфера. Никаких принципиально новых механизмов защиты от переполнения она не предоставляет, поскольку вся информация уже известна в момент вызова snprintf (в отличие от fgets!).

Еще медленнее:

Это не тот случай, когда переполнение буфера исключается автоматом, как если бы, например, функция сама распределяла бы потребное пространство в куче.

> может все-таки используешь серое вещество, вместо своей пятой точки, когда будешь писать?

Впечатляющие аргумент! Впрочем, откровенное хамство частенько сопровождает недалекость индивидуума ;)

Ладно, постарайся понять то, что я написАл. Пока у тебя неважно получается...

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

> Например, неделю назад доставленный компьютер, с предустановленной Красной Шапкой, gcc (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-34) -- ругается на for(int i=0; i<2;i++).

А --std=c99 не забыл? =)

int19h ★★★★
()
Ответ на: комментарий от Krasu

> 3) malloc+memset - это способ для истинных гуру ?

Не о том речь. Просто calloc заполняет выделенный блок памяти нулевыми _char'ами_. А указатель NULL совершенно не обязан быть представлен исключительно нулевыми битами. Т.е. в общем случае, если имеем:

int **p = calloc(1, sizeof(int*));

то предположение, что (*p == NULL) не соответствует стандарту, и, как следствие, не является переносимым. Если нужно получить массив именно с NULL'ами, то нужно выделить его через malloc, а потом пробежаться по нему и _явно_ присвоить каждому элементу NULL.

int19h ★★★★
()
Ответ на: комментарий от anonymous

> код выглядит так например:

> printf(_("my super prog, number of version is %s, compiled with bzip2 support\n"), "0.001");

> или

> std::cout<<_("my super prog, number of version is ")<<"0.0001"<<_(", compiled with bzip2 support\n")<<std::endl;

> что как думаете будет проще и легче переводить?

Я думаю, вот это:

std::cout << boost::format("my super prog, number of version is %s, compiled with bzip2 support\n") % "0.0001";

http://boost.org/libs/format/index.html

int19h ★★★★
()
Ответ на: комментарий от Die-Hard

> Никаких принципиально новых механизмов защиты от переполнения она не предоставляет, поскольку вся информация уже известна в момент вызова snprintf (в отличие от fgets!).

Это какая же информация известна в момент вызова snprintf? Предположим, у меня в строке форматирования есть %d - так вот, ты знаешь _стандартный_ способ определения размера символьного представления int'а для произвольно взятой локали (или даже для locale "C"), зная только sizeof(int)?

int19h ★★★★
()
Ответ на: комментарий от int19h

2int19h:

> А указатель NULL совершенно не обязан быть представлен исключительно нулевыми битами.

Что-то помнится мне, в С99 было прямо прописано, что "все нулевые биты" -- в точности NULL.

И, потом, мне не попадались системы, где "все нулевые биты" не представляли бы NULL.

Die-Hard ★★★★★
()
Ответ на: комментарий от int19h

int19h:

> А --std=c99 не забыл? =)

Ну, она об этом даже сама сказала :-) Однако, по умолчанию c99 мода не стоит.

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

> Что-то помнится мне, в С99 было прямо прописано, что "все нулевые биты" -- в точности NULL.

В C99 - возможно. А вот у Страуструпа я читал ровно об обратном:

5.1.1. Zero

... Zero will typically (_but not necessarily_) be represented by the bit pattern 'all-zeros' of the appropriate type.

> И, потом, мне не попадались системы, где "все нулевые биты" не представляли бы NULL.

Мне попадалось. Какой-то 32-bit extender для DOS. Null pointer там был отнюдь не равен int(0)...

int19h ★★★★
()
Ответ на: комментарий от Die-Hard

> Что-то помнится мне, в С99 было прямо прописано, что "все нулевые биты" -- в точности NULL.

Вот только сейчас посмотрел - не сказано. Единственная гарантия - что в битовых поля и значениях типа unsigned char, имеющие значение 0, все биты обнулены (ISO C99, 6.2.6.1). Сверх того сказано, что "the representations of all types are unspecified".

int19h ★★★★
()
Ответ на: комментарий от int19h

int19h:

> Предположим, у меня в строке форматирования есть %d - так вот, ты знаешь _стандартный_ способ определения размера символьного представления int'а для произвольно взятой локали (или даже для locale "C"), зная только sizeof(int)?

1.Я почему-то уверен, что на каждую работающую сегодня систему, в которой длина "%d" окажется больше 64/log_2(10)+2=22, можно найти более сотни, в которых функция snprintf() окажется затычкой, игнорирующей аргумент size.

2. А локаль не ты ли сам ставишь? Если ты выставил экзотическую локаль, (ок, поймал ее из переменных окружения), то, наверное, надо задуматься. Кстати, конкретный спецификатор "%d" от локали зависеть не будет, если ты на него флагов I не навесишь, которые есть нестандартные расширения.

Во всяком случае, информация о длине тебе доступна заранее.

Вообще, i18n в glibc -- не для слабонервных. В свете потенциальных ее плюшек, я для программ, критических к секьюрити, просто сбрасываю локаль в locale "C" (хотя и это не гарантирует безопасности).

Хотя, действительно, наверное, это тот редкий случай, когда snprintf() полезна (если форматные спецификаторы непредсказуемо зависят от локали). И часто ее так используют?

Die-Hard ★★★★★
()
Ответ на: комментарий от int19h

int19h:

> Вот только сейчас посмотрел - не сказано.

Да, я тоже посмотрел -- не так.

Гарантируется только, что любая целая константа со значением 0 и любой ее кастинг к указателю есть NULL, то есть (NULL == 0) есть абсолютная истина, как, впрочем, и (NULL = '\0').

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

> Я почему-то уверен, что на каждую работающую сегодня систему, в которой длина "%d" окажется больше 64/log_2(10)+2=22, можно найти более сотни, в которых функция snprintf() окажется затычкой, игнорирующей аргумент size.

Про snprintf я вообще молчу, т.к. не стандарт =)

Строго говоря, единственный действительно 100%-портабельный и безопасный способ для C - перегонять число в строку самому ручками, делая необходимые проверки и reallocation буфера по необходимости. В C++, к счастью, есть stringstream.

> А локаль не ты ли сам ставишь? Если ты выставил экзотическую локаль, (ок, поймал ее из переменных окружения), то, наверное, надо задуматься.

Да, сам. Но пусть даже по умолчанию стоит "C", что это меняет?

> Кстати, конкретный спецификатор "%d" от локали зависеть не будет, если ты на него флагов I не навесишь, которые есть нестандартные расширения.

Точно? Даже отображение отрицательных величин , и потенциальная расстановка разделителей между группами цифр? (я правда не знаю)

> Во всяком случае, информация о длине тебе доступна заранее.

Мне заранее доступна информация о размере числа в памяти, в char'ах. Из этого в общем случае (т.е. при неочевидном форматировании) нельзя вывести длину символьного представления данного числа.

> И часто ее так используют?

Для преобразования чисел? А что еще для этого использовать для pure C?

int19h ★★★★
()
Ответ на: комментарий от Die-Hard

> Гарантируется только, что любая целая константа со значением 0 и любой ее кастинг к указателю есть NULL, то есть (NULL == 0) есть абсолютная истина, как, впрочем, и (NULL = '\0').

Да, совершенно верно. Это, однако, не значит, что даже при sizeof(void*) == sizeof(int), значения (int)(0) и (void*)(0) побитово совпадают. Что и имелось в виду в моем случае - там нулевой указатель на самом деле имел ненулевое значение, если посмотреть на него как на int.

int19h ★★★★
()
Ответ на: комментарий от int19h

> Точно? Даже отображение отрицательных величин , и потенциальная расстановка разделителей между группами цифр? (я правда не знаю)

Вроде бы по крайней мере в C99 действительно оговаривается строгий формат для %d, не допускающий неоднозначных трактовок. Так что, действительно, зная sizeof(int) на данной платформе, несложно посчитать размер соответвующего буфера для sprintf("%d"). Извиняюсь =)

int19h ★★★★
()
Ответ на: комментарий от int19h

int19h:

>> И часто ее так используют?

> Для преобразования чисел? А что еще для этого использовать для pure C?

Я имел в виду -- для форматирования, явно завиcящего от локали, если навешать флаги ' и I, (которые, вообще говоря, НЕ C99). Без этих флагов локаль влияет только на десятичный радикс.

Die-Hard ★★★★★
()
Ответ на: комментарий от int19h

int19h:

> Так что, действительно, зная sizeof(int) на данной платформе, несложно посчитать размер соответвующего буфера для sprintf("%d").

Вообще говоря, нет, так как не известен размер char. Наверное, его можно вычислить, зная sizeof(int) и MAX_INT, но не уверен. Как я понимаю, MAX_INT -- более полезная в этом деле информация, log_10(-MIN_INT)+2 как раз и даст нам то, что надо.

Но все равно битовый размер int часто приходится определять в начале программы, хотя бы для организации циклического сдвига. Тогда уже просто, (кол-во бит)/log_2(10)+2.

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

> Вообще говоря, нет, так как не известен размер char.

Да, есть такое. Однако ж если мы забрели в C99, можно просто использовать int32_t. Кстати, его можно сэмулировать и в C89, просто объявив структуру с 32-битным битовым полем - в стандарте формат хранения целых чисел в битовых полях оговорен довольно строго.

int19h ★★★★
()

new против malloc

Подкину ещё тему для флейма :-)
Итак, new против malloc.
Понятно, что основное правило тут - не смешивать, но..
для malloc есть такая красивая функция как realloc - что вы думаете о ней? Стоит ли использовать malloc в C++, если вы знаете что массив впоследствии может быть пару (разумеется только пару, если много, то однозначно лучше использовать списки) раз ещё увеличить.
То что malloc нельзя использовать для классов - понятно.

unDEFER ★★★★★
()
Ответ на: new против malloc от unDEFER

> То что malloc нельзя использовать для классов - понятно.

почему? если бы ты написал что realloc нельзя использовать для классов, это утверждение еще бы имело право на существование. Но чем несовместимы маллок и классы?

dilmah ★★★★★
()
Ответ на: комментарий от Die-Hard

>Просто я хотел подчеркнуть, что ОЧЕНЬ распространенная точка зрения на то, что автоматическое управление памятью ведет к _автоматическому_ повышению эффективности разработки, по меньшей мере спорна.

Автор той статьи дальше приходит точно к таким же выводам --- что даже проектируя на языках высокого уровня с автоматическим управлением памятью неплохо бы помнить про malloc и free, т.к. машина думает именно в этих терминах.

dn2010 ★★★★★
()
Ответ на: new против malloc от unDEFER

>Стоит ли использовать malloc в C++, если вы знаете что массив впоследствии может >быть пару

лучше std::vector использовать

anonymous
()
Ответ на: new против malloc от unDEFER

> То что malloc нельзя использовать для классов - понятно.

Не совсем. Про placement new слышал?


int19h ★★★★
()
Ответ на: new против malloc от unDEFER

> для malloc есть такая красивая функция как realloc - что вы думаете о ней? Стоит ли использовать malloc в C++, если вы знаете что массив впоследствии может быть пару (разумеется только пару, если много, то однозначно лучше использовать списки) раз ещё увеличить.

Имхо нет. Лучше std::vector, и если так уж руки чешутся соптимизировать, вызывать reserve() для ручного контроля за реаллокацией.

int19h ★★★★
()
Ответ на: комментарий от int19h

>std::cout << boost::format("my super prog, number of version is %s, compiled with >bzip2 support\n") % "0.0001";

ага, теоритически это все хорошо,
а вот практически.

каждый модуль boost завязан на остальных,
чтобы использовать format мне придется весь boost тащить.

нафига, если можно использовать stdio?

anonymous
()
Ответ на: комментарий от anonymous

> каждый модуль boost завязан на остальных, чтобы использовать format мне придется весь boost тащить.

Вообще-то, классы в boost специально сделаны таким образом, чтобы свести к минимуму лишние зависимости. Вполне можно без особых проблем выковырять тот самый boost::format.

Кроме того, boost - это то, что _обязан_ держать у себя любой уважающий себя C++/STL-кодер =) А при линковке оно все равно туда воткнет только то, что надо...

int19h ★★★★
()
Ответ на: комментарий от anonymous

> Если ваш язык программирования позволяет выделять кусок памяти без раздумий о его последующем освобождении, то вы используете язык с управляемой памятью, и вы будете значительно эффективней программиста, использующего язык, где управление памятью производится в явном виде.

Это невсегда верно. Фактически для действительно крупного проекта надо делать своё управление памятью, хотя бы для того, чтобы небыло внезапных затыков в процессе работы программы из-за того, что сборщику мусора приспичило очистить память.

anonymous_incognito ★★★★★
()
Ответ на: комментарий от int19h

Всем спасибо за ответы.
Про malloc для классов - на самом деле я даже не пробовал - просто конструктор тогда вручную запускать? По-моему, не очень серьёзно (хотя могу, конечно, ошибаться).
Про std::vector - буду иметь ввиду.
Эх, и почему в документации (манах) ни где описаний этих стандартных классов C++ не видно?

unDEFER ★★★★★
()
Ответ на: комментарий от int19h

>Вообще-то, классы в boost специально сделаны таким образом, чтобы свести к .>минимуму лишние зависимости.
>Вполне можно без особых проблем выковырять тот самый boost::format.

а ты пробовал?

мне как-то нужен был smart_ptr ни фига его без значительного куска
boost не выковариешь.

так что не надо ляля

anonymous
()
Ответ на: комментарий от anonymous

> вообще языки учат не по манам а по книжкам,
> а маны просто помогают при использование
А чего хочу? Помощи при использовании и желаем.
За ссылку спасибо - хотя в инете я уже тоже нашёл их описание.

unDEFER ★★★★★
()
Ответ на: комментарий от unDEFER

> Про malloc для классов - на самом деле я даже не пробовал - просто конструктор тогда вручную запускать? По-моему, не очень серьёзно (хотя могу, конечно, ошибаться).

Есть такая вещь - placement new называется. Это тот же operator new, только он не выделяет память, а создает объект (и вызывает конструктор) в уже выделенной. Где-то вот так:

new (buf) foo("bar");

Аналогично delete. Там единственные грабли - выделенный тобой блок памяти должен иметь корректный alignment для данного типа.

Используется редко, но иногда бывает полезно. Скажем, таким образом можно сделать что-то типа union, но из объектов с конструкторами etc =)

int19h ★★★★
()
Ответ на: комментарий от anonymous_incognito

>Фактически для действительно крупного проекта надо делать своё >управление памятью, хотя бы для того, чтобы небыло внезапных затыков >в процессе работы программы из-за того, что сборщику мусора >приспичило очистить память.

1) Сборщик мусора можно настраивать, отключать в критических случаях

2) Выделением памяти можно управлять даже со сборщиком мусора

3) Если очень хочется можно не делать мусора вообще, хотя это может быть довольно замысловато, но все равно секьюрнее и производительнее, чем управлять памятью со всякими "умными указателями".

4) Сборщики мусора бывают многопоточными и если Вы не наделаете целую гору мусора, что в принципе считается дурным тоном, то остановка приложения не предвидится, в худшем случае незаметное замедление.

5) Проект проекту рознь. Для какого-нибудь мегакрупного проекта может быть далеко наплевать даже на секундную остановку в определенных местах. Существуют сборщики мусора для программ с жесткими требованиями по памяти и производительности, например для 3D игр на приставках.

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

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.