Страница 1 из 2

Про ссылки и указатели (продолжение)

Добавлено: 08 ноя 2004, 13:53
Absurd
DeeJayC прав, COut надо передавать по ссылке.
Может оказаться так что одна или несколько ссылок на StringBuffer будут неучтены, поскольку конструктор CString не отработает.
Тогда StringBuffer будет удален раньше времени и закончится это Protection fault'ом.
Программист всегда предпочитает пользоваться теми средствами, которыми владеет лучше
Это да. Нормальными средствами тяжело владеть.
Любое более-менее сложное решение подразумевает состыковку. Это нормальная часть работы программиста, работающего в команде.
Сейчас заставляю работать один модуль, написанный каким-то Шакилой, который в качестве параметра берет не List, а Vector, вместо потока - имя файла итп. Требует пермишены на запись для своих конфигов, которые он только читает и не модифицирует.
Какой бы это ужас был, если бы это было не на Яве, а на С++ :()
Насчет мудаков и исключений - не вижу корреляции.
В C++ нету исключений. Использовать то, чего нет - это мудачество.
Нету ключевого слова finally, нету уборки мусора.
Я не говорю, что нужно делать уборку мусора обязачельно - достаточно по дефолту делать,
скажем, подсчет ссылок, и включить в библиотеку хедер <gc.h>,
который можно было бы использовать опционально.
auto_ptr - это вообще чудо. Он меняет свое содержимое при присваивании.
Такой ужас надо еще постараться придумать.
Откуда пошло слово мудак:
Обычно монголы кастрировали русских мужчин.
Но для некоторых это была большая трагедия, и монголам было их жалко.
Поэтому им усекали спермоносные каналы, и количество мужских гормонов не менялось.
Трахаться они могли, могли эякулировать чистым предстательным соком,но детей они
иметь не могли.
Отсюда пошло слово "мудак" - то есть вроде бы при мудях, а вроде бы и нет.

Добавлено: 09 ноя 2004, 17:32
Eugie
Может оказаться так что одна или несколько ссылок на StringBuffer будут неучтены, поскольку конструктор CString не отработает.
Тогда StringBuffer будет удален раньше времени и закончится это Protection fault'ом.
Какие ссылки, где учтены? В огороде бузина... ;) Absurd, уверяю тебя: передача параметра по ссылке вполне безопасна и по сути эквивалентна передаче по указателю. Если возражаешь, плиз приведи конкретный пример, а не общие слова.
В C++ нету исключений. Использовать то, чего нет - это мудачество.
В C++ есть исключения (см. throw, try, catch). Другое дело, что C++ модель exception handling низкоуровневая - все надо делать самому. Да, это неудобно, и, главное, трудоемко. Конечно, приятнее пользоваться развитой иерархией исключений какой-нить среды типа .NET
Нету ключевого слова finally, нету уборки мусора.
C++ такой язык - предоставляет минимум готовых решений, но при этом позволяет реализовать практически все самому. Согласен, что с finally и GC удобнее, особенно когда привык. К хорошему вообще быстро привыкаешь :)

PS. Спасибо, что просветил по вопросу этимологии :) М***ки, в сущности, вызывают сочувствие как невинные жертвы татаро-монгольского ига :) ))

Добавлено: 10 ноя 2004, 17:04
Eugie
Если кто-то ссылается на объект a, b или c через ссылку, тогда получается что
На строку Hello world ссылаются четыре или больше раз, а счетчик ссылок равен 3.
Вот тут ты не прав. Внутренний счетчик ссылок на строку не инкрементируется при передаче параметра по ссылке. Дело в том, что он может модифицироваться только при вызове конструктора копирования или при присваивании, а при передаче параметра по ссылке ни того, ни другого не происходит.

Добавлено: 10 ноя 2004, 17:19
AiK
Absurd, ты зачем шифруешься? :)

Добавлено: 12 ноя 2004, 13:48
Absurd
Внутренний счетчик ссылок на строку не инкрементируется при передаче параметра по ссылке.
Я это и имел в виду. Передали кому-то CString и не учли новую ссылку. В многопоточной среде может случиться преждевременное обнуление счетчика.
Absurd, ты зачем шифруешься?
Глюк форума

Добавлено: 15 ноя 2004, 12:12
Eugie
Я это и имел в виду. Передали кому-то CString и не учли новую ссылку. В многопоточной среде может случиться преждевременное обнуление счетчика.
Absurd, ты не мешай в одну кучу внутренние ссылки класса CString (назовем их для отличия референциями) и ссылки в смысле С++ (далее С++-ссылки). При передаче куда-то ссылки на объект мы и не должны увеличивать счетчик референций, поскольку он предназначен для учета копий данного CString-объекта, а не С++-ссылок на него. А копию объекта мы в этом случае не создаем. Логика подсчета референций CString (ты сам ее описал) не конфликтует с возможностью объявить произвольное число С++-ссылок на CString. С++-ссылка сама не является объектом и не может пережить связанный с ней объект по определению, т.к. 1) должна быть обязательно инициализирована; 2) инициализирующий объект не может иметь область видимости меньшую, чем связанная с ним ссылка. Т.е. защита от дурака здесь реализована средствами самого языка.

В случае многопоточности ситуация сложнее. С одной стороны, - ты, наверное, знаешь - модификация референций в CString потокобезопасна. С другой - можно исхитриться и передать в поток ссылку на временный объект, который к моменту обращения к нему из потока будет разрушен. Но, 1) это не так просто сделать, и 2) это не есть специфика класса CString. Проблема будет в случае любого типа данных (см.пример), просто такое действие будет явно деструктивным. Любую защиту ведь можно поломать, было бы желание :)

Пример намеренного нарушения правил работы с ссылками в многопоточной среде:

Код: Выделить всё

class A {
    int& m_r;
public:
    A(int& r): m_r(r) {}
    int GetByRef() { return m_r; }
};

unsigned long thrd_hdl;
unsigned thrd_addr;

unsigned __stdcall thread_routine(void *p)
{
    A* pa = reinterpret_cast<A*>(p);
    cout << pa->GetByRef() << endl;
    return 0;
}

void f()
{
   // Передаем в создаваемый поток ссылку на временную переменную типа int 
   // (через указатель на статичесий объект, т.к.напрямую нельзя). К моменту
   // вызова thread_routine ссылка становится инвалидной.
   // А если объявить static int n - все будет OK.
   int n = 1;
   static A a(n);

   thrd_hdl = _beginthreadex(
       NULL, 
       0, 
       thread_routine, 
       (void *)&a, 
       0, 
       &thrd_addr);
}

void main()
{
    f();
    Sleep(1000L);
}
PS. IMHO, надо бы вернуть топик в раздел C/C++ - вещи-то обсуждаем весьма серьезные. За вычетом филологических вопросов, конечно :)

Добавлено: 17 ноя 2004, 20:13
Absurd
При передаче куда-то ссылки на объект мы и не должны увеличивать счетчик референций, поскольку он предназначен для учета копий данного CString-объекта, а не С++-ссылок на него.
Какая разница? Все равно это нарушение политики, которую предстравляет смарт-указатель. В С++ есть соглашение (contract), что смарт - указатели должны пользоваться конструктором копирования и operator=() для отслеживания жизни указуемого объекта.
Если мы пользуем ссылку на смарт - указатель, то мы обходим его политику.

Добавлено: 18 ноя 2004, 17:49
Eugie
CString - не смарт-указатель, хотя тоже умеет считать ссылки.
Absurd, приведи мне плиз конкретный пример кода, где передача CString в функцию по ссылке небезопасна. Иначе спорить можно еще долго, а время - деньги :)

Добавлено: 22 ноя 2004, 13:10
Absurd
Absurd, приведи мне плиз конкретный пример кода, где передача CString в функцию по ссылке небезопасна
Указатель - это наиболее общий способ передачи ссылки на объект. Ссылки вторичны и служат инструментом для написания базовых примитивов в программе.
Значит, надо пользоваться указателями для соблюдения порядка в API.