Подскажите, пожалуйста, какую оптимизацию проведет компилятор в таком коде:
void MyClass::clear() noexcept
{
MyClass tmp;
this->swap(tmp);
}
Или можно сразу написать так (сделает ли так компилятор?):
void MyClass::clear() noexcept
{
this->swap(MyClass());
}
Компилятор MS Visual-C++. Во втором примере немного смущает то, что в функцию-метод класса swap
, принимающую неконстантную ссылку, передается объект «без переменной». Как бы ничего от этого формально не страдает, но выглядит немного возбуждающе.
void MyClass::swap(MyClass& other) noexcept
{
using std::swap;
swap(this->m_number, other.m_number);
}
Ладно, вот код - простейший класс.
class Test {
public:
Test() {}
Test(int x):val_(x){}
Test(const Test& t):val_(t.val_) {}
Test(Test&&t) :val_(t.val_) {}
Test& operator = (const Test& t) {
val_ = t.val_;
return *this;}
Test& operator = (Test&& t) {
val_ = t.val_; t.val_ = 0;
return *this;}
~Test() {}
int val() const { return val_; }
void swap(Test& t) { ::swap(val_, t.val_); }
void clear1() noexcept
{
Test tmp;
this->swap(tmp);
}
void clear2() noexcept
{
this->swap(Test());
}
private:
int val_ = 0;
};
int main(int argc, const char * argv[])
{
Test x(5), y(6);
x.clear1();
y.clear2();
}
Компилируется это чудо только с предупреждением (в общем-то, я предупреждал в комментариях)
test.cpp(37): warning C4239: нестандартное расширение: аргумент: преобразование "Test" в "Test &"
test.cpp(37): note: Неконстантная ссылка может быть связана только с левосторонним значением
Если использовать это "нестандартное расширение", то ассемблерный код VC++ 2017 идентичен при включенной оптимизации и идентичен с точностью до одной ассемблерной команды при выключенной - в одном месте clear1()
использовано обращение к памяти, в то время как в clear2()
- к регистру.
Так что пользуйтесь тем способом, который не вызывает предупреждений.
P.S. Впрочем, еще можно - если хотите - добавить перегрузку swap
для rvalue.
Я собрал Ваш пример (минимальный) в gcc.godbolt.org. И решил посмотреть результат оптимизации. Он приятно удивил. Функция clear (первый вариант) стала такой
MyClass::clear():
mov DWORD PTR [rdi], 0
ret
То есть, компилятор выбросил создание новой переменной и вызов swap. А просто занулил переменную. Это делает gcc c 4.9.4 и новее даже на уровне оптимизации O1 (более младшие нет смысла проверять). Clang похоже такое умеет делать с 3.7. Как по мне - компилятор управился просто на отлично.
Второй вариант clear не компилируется gcc/clang - поэтому, проверить результат компиляции сложно.
2017 студия делает такое же. Но при этом она компилирует оба варианта функции clear.
Вывод. Пишите код просто и явно. Компилятор сам все сделает. И сделает явно не хуже ручной оптимизации.
А также может прийти доброжелатель, который решит добавить ключик '/Za', который отключает подобные "особенности компилятора студии" и все... код не будет собираться.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Итак имеется два оператора присваивания - копирующий и перемещающий, например такие:
У меня есть QListView и модель для него, унаследованная от QAbstractListModelМне необходимо отображать элементы модели при помощи кастомных виджетов
Я бы хотел таким образом получить максимальный элемент field, но не понимаю, как получить возвращаемое значение