Главная страница Случайная страница Разделы сайта АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
💸 Как сделать бизнес проще, а карман толще?
Тот, кто работает в сфере услуг, знает — без ведения записи клиентов никуда. Мало того, что нужно видеть свое раписание, но и напоминать клиентам о визитах тоже.
Проблема в том, что средняя цена по рынку за такой сервис — 800 руб/мес или почти 15 000 руб за год. И это минимальный функционал.
Нашли самый бюджетный и оптимальный вариант: сервис VisitTime.⚡️ Для новых пользователей первый месяц бесплатно. А далее 290 руб/мес, это в 3 раза дешевле аналогов. За эту цену доступен весь функционал: напоминание о визитах, чаевые, предоплаты, общение с клиентами, переносы записей и так далее. ✅ Уйма гибких настроек, которые помогут вам зарабатывать больше и забыть про чувство «что-то мне нужно было сделать». Сомневаетесь? нажмите на текст, запустите чат-бота и убедитесь во всем сами! Rvalue ссылки
Разница между lvalue (которые могут использоваться слева от оператора присваивания) и rvalue значениями (которые могут использоваться справа от оператора присваивания) ведут свое начало от Кристофера Страчи (Christopher Strachey) («папы» дальнего родственника С++ под названием CPL и его денотационных семантик). В языке С++ неконстантная ссылка может быть связана с lvalue, константная ссылка – с lvalue или rvalue, но не существует ничего, что может быть связано с неконстантным rvalue значением. Это сделано для защиты от изменения значений временных объектов, которые будут уничтожены до того, как новым значением можно будет воспользоваться. Например: void incr(int& a) { ++a; } int i = 0; incr(i); // i буде равняться 1 incr(0); // ошибка: 0 не является lvalue
Если бы вызов incr(0) был бы разрешен, то тогда либо будет увеличено значение временной переменной, которое никто не сможет увидеть, либо, что еще хуже, 0 станет равен 1. Последний вариант звучит глупо, но подобный баг был в ранних версиях компилятора Fortran, который позволял втихую изменить ячейку памяти, хранившую 0. Пока все хорошо, но давайте рассмотрим следующий пример: // " старый добрый обмен значениями" template< class T> swap(T& a, T& b) { T tmp(a); // теперь у нас есть две копии a a = b; // теперь у нас есть две копии b b = tmp; // теперь у нас есть две копии tmp (aka a) }
Если для типа T копирование элементов является дорогой операцией, как например, для типов string или vector, операция swap также становится достаточно дорогой операцией (поэтому в стандартной библиотеке у нас есть специализированные версии методов swap для строки и вектора). Обратите внимание на интересный момент: мы вообще не хотим делать никаких копий. Мы просто хотим поменять значения a, b и tmp. Для перемещения, а не копирования аргументов в С++11 мы можем определить «конструкторы перемещения» (move constructors) и «операторы перемещения» (move assignments): template< class T> class vector { //... vector(const vector&); // конструктор копирования vector(vector& &); // конструктор перемещения vector& operator=(const vector&); // обычное присваивание vector& operator=(vector& &); // оператор перемещения }; // обратите внимание: конструктор и оператор перемещения // принимают неконстантные & & // они могут (и обычно делают) изменяют свои аргументы
& & означает “rvalue-ссылку”. rvalue-ссылки могут быть связаны только с rvalue (но не с lvalue). X a; X f(); X& r1 = a; // связывает r1 с a (lvalue) X& r2 = f(); // ошибка: f() возвращает rvalue; X& & rr1 = f(); // ok: связывает rr1 с временным объектом X& & rr2 = a; // ошибка: a – это lvalue
Идея семантики перемещения заключается в том, что вместо создания копии, мы можем просто взять значение из источника и заменить его дешевым значением по умолчанию. Например, для выражения s1=s2 с поддержкой перемещения, символы строки s2 скопированы не будут; вместо этого, строка s1 будет рассматривать символы строки s2, как свои собственные и удалит свои исходные данные (возможно передаст их строке s2, которая вскоре будет удалена). Откуда мы знаем, что перемещение данных из источника является безопасным? Мы говорим об этом компилятору: template< class T> void swap(T& a, T& b) // " идеальный обмен значениями" (почти) { T tmp = move(a); // может сделать a недействительным a = move(b); // может сделать b недействительным b = move(tmp); // может сделать tmp недействительным }
move(x) означает «вы можете рассматривать x в качестве rvalue». Возможно, было бы лучше, если бы move() назывался rval(), но move() уже используется многие годы. Шаблонная функция move() может быть написана на С++11 (см. " Brief introduction to rvalue references") с помощью rvalue-ссылок. Rvalue-ссылки могут использоваться для создания идеального механизма перенаправления (forwarding). В стандартной библиотеке С++11 во все контейнеры добавлены конструкторы и операторы перемещения. Также операции добавления новых элементов, такие как insert() и push_back() содержат версии, принимающие rvalue-ссылки. Конечным результатом является то, что производительность стандартных контейнеров и алгоритмов тихо (без вмешательства пользователя) была улучшена за счет уменьшения необходимости копирования. См. также:
|