Pull to refresh

Comments 13

Sergey Kosarevsky,
мне одному так тяжело код с таким стилем читать? Или я очень придирчив?
А как Вам, например, вот такой стиль:

FArchive& operator<<( UObject*& Object )
{
	// Avoid duplicate entries.
	if ( Object != NULL && !SerializedObjects.Contains(Object) )
	{
		SerializedObjects.Add(Object);
		if ( !Object->IsA(UField::StaticClass()) 
		&&	(Object->NeedsLoadForClient() || Object->NeedsLoadForServer()) )
		{
			if (EditorContentPackages.Contains(Object->GetOutermost())
			&&	Object->GetOutermost() != Object )
			{
				ReferencedEditorOnlyObjects.Add(Object);
			}

			Object->Serialize(*this);
		}
	}
		
	return *this;
}


См. UnrealEngine\Engine\Source\Runtime\Engine\Private\ErrorChecking.cpp
Понял, я придирчив. Спасибо
Очень впечатляет, однако это скорее демонстрация возможностей gcc оптимизатора. Как видно на последнем листинге, этот код не делает вообще НИЧЕГО в рантайм. Число итераций предвычисляется во время компиляции и все, всего одна инструкция, естественно что минимально рабочий код на может быть предвычислен.
Мне кажется ценность статьи в другом — часто во время тестирования надо как раз надурить оптимизатор и избежать оптимизации циклов, вот тут то мы теперь и будем знать что делать.
Статья именно о том, что атомики мешают оптимизатору. И как раз показанный результат очень нагляден в этом плане.

Для избежания оптимизации циклов достаточно объявить переменную цикла как volatile.
Очевидно, пока вызываемая функция не завершится, смарт-указатель в вызывающем коде будет жить, поэтому объект не будет уничтожен.

У меня все функции принимают обычный указатель, а не умный.
Вместо
void Process(const clPtr<clTestObject>& ptr);
я пишу
void Process(const clTestObject* ptr);

Мне кажется, так код выглядит проще. А если компилятор не заинлайнит Process, код этой ф-ции будет ещё и короче (т.к. не надо доставать указатель из контейнера).

В шаблоне clPtr есть оператор преобразования к указателю, поэтому в месте вызова функции я пишу так же — Process(smartPtr), не надо писать Process(smartPtr.get()).

А если ссылка на смарт указатель это ссылка на поле объекта?
Тогда такая автоматическая замена не сработает. Хотя случай очень редкий.
Нужно отразить семантику функции в названии (например, SetPointer(clPtr<clTestObject>& dstptr)), тогда при написании сигнатуры функции будет понятно, зачем нужна ссылка на указатель.
Возникает вопрос, зачем вообще передавать в функцию умный указатель? Если эта функция не оставляет у себя копий указателя — то лучше передавать в нее простой указатель, а не умный. А если она оставляет копии — то в любом случае придется выполнять операции со счетчиком ссылок. Оптимизация за счет передачи ссылки на умный указатель будет возможна и в этом случае. Но такая оптимизация — это исключение вызовов конструктора и деструктора при передаче объекта по значению — возможна для любого нетривиального типа объектов, а не только умных указателей.
Об этом и говорят Александреску, Саттер и Майерс.
C++ язык маркетологов. Ежу блин понятно, что если передаваемый в функцию объект больше разрядности регистра, то нужно передовать по ссылке.

С новыми стандартами к этому правилу добвляется еще то, что если владение объектом передается в вызываемый код, то нужно передавать по значению, из за move семантики.
Помимо атомарных операций будет экономия на SEH фреймах, если в пределах тела функции нет ARC объектов.
Ну а также постоянное копирование умных указателей может замедлить выполнение паралельных задач
Sign up to leave a comment.

Articles