Изменены сроки приёма экзаменов Microsoft

До вчерашнего дня Microsoft планировал прекратить приём экзаменов 70-643, 70-647 и 70-680 31 июля этого года. Таким образом прекращалась сертификация специалистов по треку MCITP: Enterprise Administrator on Windows Server 2008. Среди администраторов желавших получить сертификацию это вызывало бессонные ночи подготовки, наравне с недовольством, так как официальных материалов для аналогичной сертификации по Windows 2012 на данный момент нет.

Вчера срок приёма экзаменов был изменён. Теперь экзамены будут приниматься до 31 января 2014 года включительно.

ссылка на оригинал статьи http://habrahabr.ru/post/185148/

Умение видеть абстракции

Моему сыну, как и многим мальчишкам, нравятся автомобили. Причём чем они больше и необычнее — тем больше нравятся. Когда мы идём по улице, а мимо проезжает эвакуатор или снегоуборочная машина, он неизменно дёргает меня за руку, указывает на заинтересовавший его объект и говорит: «Папа, б-р-р!». Говорит он так потому, что ему один год и вышеуказанные два слова составляют 40% его словарного запаса. Тем ни менее, в общем мысль понятна — обратить внимание на автомобиль. Давайте подумаем, каким образом ребёнок в возрасте 8-10 лет сказал бы своему сверстнику то же самое. Что-то вроде «Ух-ты, смотри какая крутая тачка!», да? Мысль та же, но обратите внимание — уже шесть слов вместо двух. И, наконец, представьте, каким образом то же самое скажет человек лет в тридцать: «Эй, смотри, да это же Ferrari California 2008-го года выпуска с двигателем V8 мощностью в 260 лошадиных сил и 7-ми скоростной коробкой-автоматом! Она до сотни разгоняется за 3.9 секунды!». Да, здесь уже больше деталей, но, если вы не автомеханик или фанат Ferrari — они вам скорее всего не нужны и не важны. Основная же мысль — всё та же, что и в «Ух-ты, смотри какая крутая тачка!» или «Папа, б-р-р!». Но выражена она уже в 30 слов.

Вы заметили, как абстракция «интересный автомобиль» обросла деталями и нюансами, стала занимать существенно больше места в тексте и времени на понимание, анализ и ответ? То же самое происходит и с программным кодом.

О чём вообще идёт речь

По моему мнению, основная характеристика хорошего программиста это не глубокие знания математики, не 100 лет опыта за плечами, не знания кучи языков и библиотек, не %куча_других_неважных_вещей%, а именно умение видеть абстракции. Не только видеть, конечно, а ещё и проектировать, использовать, исправлять и т.д. Но факт есть факт. Успех какого-нибудь популярного сегодня продукта (подставьте сюда свою любимую ОС, браузер, игру — да что угодно) определён именно тем, насколько хорошо спроектирована его архитектура, насколько хорошо высокоуровневые части отделены от низкоуровневых и друг от друга.

Посмотрите на «умершие» проекты. Очень редко они погибают от того, что программист не смог на 10% повысить скорость работы, или потому что не смогли прикрутить нужную библиотеку. Чаще всего причина закрытия формулируется в духе «существующая архитектура делает принципиально невозможным дальнейшее развитие». Вот она, ошибка в видении абстракций. Кто-то когда-то давно не увидел, что несколько сущностей на самом деле являются одной, или что одна может иметь несколько представлений, или что на самом деле не клиент должен дёргать сервер, а наоборот, или что в протокол неплохо бы заложить возможность расширения — и вот он, грянувший спустя годы гром последствий.

Паттерны

В современном мире программирования есть такая штука как «паттерны». Ну, знаете, книга банды четырёх, всякие там фабрики\синглтоны\обёртки\наблюдатели\фасады\мосты. Отношение программистов к паттернам неоднозначно. Есть лагерь любителей паттернов, которые справедливо утверждают, что это всё — квинтэссенция десятилетий лучшего программерского опыта, проверенные вещи и надо не тормозить, а использовать наработки по полной. И есть лагерь противников паттернов, которые пеняют им на излишнюю сложность (3-5 классов на реализацию одной идеи — вполне типично для средненького паттерна), говорят, что изучение паттернов подобно школьной зубрёжке — когда просто учишь что-то без понимания причин, следствий и вариантов именно целевого использования.

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

Другие паттерны являются откровенным мусором. Просто потому, что вот эти два класса находятся в третьем, унаследованы от четвёртого и вызывают методы пятого — они не создают абстракцию. Возможно, они каким-то образом ускоряют код или обходят какое-то ограничение языка, но вот целостной идеи не формируют. Это трудно понять, невозможно запомнить и это вызывает праведный гнев в рациональном мозгу программиста. Примерно как случайный набор слов, не формирующий предложения — у читателя. Пижама сладкий прыгать Луна вопреки быстро люк?

Инструменты

К сожалению, современные средства разработки не дают хороших автоматических средств для того, чтобы видеть абстракции в проекте. Да, вы можете увидеть интерфейсы или абстрактные классы в коде — но не факт, что это то, что составляет настоящую абстракцию. Какой-то определённый слой логики может содержать в себе десятки интерфейсов, а другой — иметь всего один класс (и тот — просто пустая обёртка вокруг чего-то другого). Мы можем с помощью IDE увидеть классы, методы и переменные — но мы не видим реального разделения проекта на слои. Всё остаётся на совести программиста. К счастью, у нас сегодня есть возможность выносить код в отдельные модули, у нас есть пространства имён, интерфейсы, дельные советы по рефакторингу и инструменты для его осуществления. Написать хорошо разделённый на отдельные модули код — возможно. И это важнее, чем написать быстрый код. Конечно, «модульный код» не на 100% равно «идеальный код», но очень и очень к этому близко.

Пример плохого кода

Несколько лет назад был пик популярности текстового редактора Notepad++. Десятки миллионов загрузок, приятный минималистичный интерфейс, плагины. Начало было очень хорошее, ничто не предвещало беды. За последние пару лет данный текстовый редактор сдулся и фактически застопорился в своём развитии. Вот график его загрузок.

В чём же причины? Я не берусь называть их все, но вот одна. Давайте посмотрим на один файл из его исходников.
NppBigSwitch.cpp

Внимательнее разберём некоторые части этого кода.

Непонимание понятия 'имя переменной'.

Macro m = _macro; 

Имя переменной — это не имя регистра процессора. Главная задача имени переменной не адресовать ячейку в памяти, а объяснить, что за данные в ней находятся. Просто для адресации можно было бы один раз в начале выделить массив в памяти и бегать по нему указателями. Именно имя переменной является той абстракцией, которая упрощает понимание кода. Здесь, как видим, не упрощает.

Непонимание работы систем контроля версий

/* 		case NPPM_ADDREBAR : 		{ 			if (!lParam) 				return FALSE; 			_rebarTop.addBand((REBARBANDINFO*)lParam, false); 			return TRUE; 		}  		case NPPM_UPDATEREBAR : 		{ 			if (!lParam || wParam < REBAR_BAR_EXTERNAL) 				return FALSE; 			_rebarTop.reNew((int)wParam, (REBARBANDINFO*)lParam); 			return TRUE; 		}  		case NPPM_REMOVEREBAR : 		{ 			if (wParam < REBAR_BAR_EXTERNAL) 				return FALSE; 			_rebarTop.removeBand((int)wParam); 			return TRUE; 		} */ 

Старому ненужному коду нужно быть удалённым с комментарием в отдельном коммите о том почему он был удалён. Если это ещё не дописанная функциональность — её место в отдельной ветке. Просто так держать нагромождения закомментированого кода в файлах проекта — значит не понимать идеи систем контроля версий.

Непонимания того, где важнее скорость работы программы, а где — скорость работы программиста

LRESULT Notepad_plus::process(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { ...  // тут 1800 строк кода ... } 

Ничего так размерчик для одной функции, да? Автор, наверное, пытался сэкономить целый десяток наносекунд на вызов каждого отдельного кусочка кода через отдельную функцию. Молодец, сэкономил. И получил код, в котором противно копаться и нужно тратить кучу времени на понимание и исправление.

Непонимания абстракций 'флаг', 'константа', 'магическое число'.

nmdlg->Items[i] = 0xFFFFFFFF; // indicate file was closed ... if ((lParam == 1) || (lParam == 2)) ... long view = MAIN_VIEW; view <<= 30; return view|i; 

Что такое 0xFFFFFFFF, 1, 2 и 30? Ах да, 0xFFFFFFFF — означает что файл был закрыт. Какой чудесный комментарий, как всё наглядно! Было, видимо, очень быстро и удобно просто набросать цифры в код — компилируется ведь. Нет времени объяснять, поехали дальше, да?

Отсутствие абстракции над кодировками

				case COPYDATA_FILENAMESA : 				{ 					char *fileNamesA = (char *)pCopyData->lpData; 					CmdLineParams & cmdLineParams = pNppParam->getCmdLineParams(); #ifdef UNICODE 					WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); 					const wchar_t *fileNamesW = wmc->char2wchar(fileNamesA, CP_ACP); 					loadCommandlineParams(fileNamesW, &cmdLineParams); #else 					loadCommandlineParams(fileNamesA, &cmdLineParams); #endif 					break; 				}  				case COPYDATA_FILENAMESW : 				{ 					wchar_t *fileNamesW = (wchar_t *)pCopyData->lpData; 					CmdLineParams & cmdLineParams = pNppParam->getCmdLineParams(); 					 #ifdef UNICODE 					loadCommandlineParams(fileNamesW, &cmdLineParams); #else 					WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); 					const char *fileNamesA = wmc->wchar2char(fileNamesW, CP_ACP); 					loadCommandlineParams(fileNamesA, &cmdLineParams); #endif 					break; 				} 			}              return TRUE;         } 

В каждом месте, где имеет значение в юникоде скомпилирована программа или нет, мы видим конструкции, нагружающие мозг программиста ненужными в данный момент вещами. Даже в Win32 API, где многие функции имеют юникодную и неюникодную версии мы не думаем каждый раз что вызывать, просто пишем «MessageBox», а благодаря макросам это заменяется на MessageBoxA или MessageBoxW. Это позволяет подняться над данным уровнем, отключить мозг от необходимости помнить об этой детали. Авторам Notepad++ такой путь, видимо, кажется слишком лёгким.

Отсутствие слоя абстракции над UI-примитивами операционной системы

::MoveWindow(_rebarTop.getHSelf(), 0, 0, rc.right, _rebarTop.getHeight(), TRUE); ... ::SendMessage(_statusBar.getHSelf(), WM_SIZE, wParam, lParam); 

Каждый раз, когда нам нужно передвинуть окно, спрятать его или выполнить какое-либо иное действие с элементом интерфейса — дёргаются напрямую функции Win32 API. Никаких библиотек интерфейса, никаких обёрток, классов — ничего. В итоге — куча лишнего и дублирующегося кода, абсолютная непортируемость на другие ОС, все недостатки Win32 API — прямо внутри нашего кода. Причём авторы выставляют такой подход как преимущество продукта, дескать, никаких лишних компонентов! Это просто ужас. Сотые доли процента прироста производительности (в лучшем случае) — и ад в исходниках.

Как результат всего вышеперечисленного, разработка Notepad++ является катастрофически сложным и медленным делом. Мой патч, исправляющий пару важных для меня багов висит в списке «на рассмотрении» уже полгода, вместе с почти 200 другими патчами. Автор, конечно, время от времени что-то из них принимает, но вы сами понимаете — делать это быстро с такой кодовой базой абсолютно невозможно. Мне очень жаль показавшийся мне когда-то хорошим редактор, но вы видите сами — смерть неизбежна.

Пример хорошего кода

Возможно, вам известна такая популярная библиотека как Qt — о ней в последнее время много пишут на Хабре. Я, опять-таки, не берусь утверждать, что знаю лучше всех все причины её успеха, но вот вам одна из них. Вся библиотека построена на прекрасном ядре абстракций: тут есть абстракции от платформы, от сети, от элементов интерфейса ОС, от кодировок, да практически от чего угодно. Взглянув на любой компонент Qt нам не нужно лезть сильно глубоко вниз или вверх, чтобы понять как он работает. Причём всё это не благодаря хорошей документации, а из-за кода самой библиотеки.

Давайте посмотрим на один из заголовочных файлов библиотеки Qt.

qpdfwriter.h

#ifndef QPDFWRITER_H #define QPDFWRITER_H  #include <QtCore/qobject.h> #include <QtGui/qpagedpaintdevice.h>  QT_BEGIN_NAMESPACE   class QIODevice; class QPdfWriterPrivate;  class Q_GUI_EXPORT QPdfWriter : public QObject, public QPagedPaintDevice {     Q_OBJECT public:     explicit QPdfWriter(const QString &filename);     explicit QPdfWriter(QIODevice *device);     ~QPdfWriter();      QString title() const;     void setTitle(const QString &title);      QString creator() const;     void setCreator(const QString &creator);      bool newPage();      void setPageSize(PageSize size);     void setPageSizeMM(const QSizeF &size);      void setMargins(const Margins &m);  protected:     QPaintEngine *paintEngine() const;     int metric(PaintDeviceMetric id) const;  private:     Q_DISABLE_COPY(QPdfWriter)     Q_DECLARE_PRIVATE(QPdfWriter) };  QT_END_NAMESPACE  #endif 

Не пугайтесь возможно незнакомых вам макросов — не о них речь. Я хочу обратить ваше внимание на другую вещь. Заметьте, в этом классе нет приватных свойств. И почти ни в одном другом классе Qt — тоже нет. Вернее, на самом деле в каждом из них есть ровно по одной приватной переменной — это неявно объявленный через макрос Q_DECLARE_PRIVATE указатель на подкласс, в котором уже и находятся все свойства и часть приватных методов. Сделано это по официальному объяснению для обеспечения бинарной совместимости — получается что данный класс в любой версии Qt имеет один и тот же размер (поскольку место для хранения одного указателя константно в пределах платформы) и его можно спокойно передавать туда-сюда между модулями, не боясь каких-нибудь там segmentation fault.

На самом деле для меня вся прелесть этого решения в другом. Смотрите — мы открываем заголовочный файл и что же мы видим? Только публичные методы. Вы впервые видите этот заголовочный файл (да и вообще библиотеку Qt, может быть) — но вы ведь уже поняли, что это за класс и как его использовать, правда? Все внутренности изящно скрыты в приватном подклассе. К сожалению, классический С++ заставляет программиста смешивать в заголовочном файле и то, что нужно внешнему пользователю класса и его внутренности. Но в Qt при чтении заголовочного файла — мы видим чёткое послание от разработчиков Qt: «Внутренности этого класса тебе не нужны. Не твоё дело что там и как, это абстракция — используй её через публичные методы.». И это прекрасно, чёрт возьми! Я хочу видеть все библиотеки в подобном стиле. Покажите мне нужные мне вещи сразу и спрячьте ненужные так, чтобы их нужно было искать долго и трудно. За этим подходом будущее, я уверен.

Выводы

Большинство хороших советов для программистов типа «Используйте рефакторинг», «Применяйте хорошие паттерны», «Преждевременная оптимизация — зло», «Не пишите больших функций», «Не заводите глобальных переменных» на самом деле являются выводами из более общего совета «Умейте видеть абстракции».

Приятного программирования.

ссылка на оригинал статьи http://habrahabr.ru/post/185144/

Обзор новых возможностей С++14: Часть 1

В апреле в Бристоле прошла встреча комитета С++, на которой были рассмотрены первые предложения по внесению изменений в новый стандарт С++14. Все рассматриваемые в этой статье изменения были одобрены на этой встрече и уже занимают свое почетное место в последней версии черновика нового стандарта (N3690 от 15 мая 2013).

Краткий перечень:

  • Автоматическое определение типа возвращаемого значения для обычных функций
  • Обобщенная инициализация захваченных переменных лямбд с поддержкой захвата-по-перемещению
  • Обобщенные (полиморфные) лямбда-выражения
  • Упрощенные ограничения на создание constexpr функций
  • Шаблоны переменных
  • exchange
  • make_unique
  • Обособленные строки
  • Пользовательские литералы для типов стандартной библиотеки
  • optional
  • shared_mutex и shared_lock
  • dynarray

Изменения в самом языке

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

Начиная с С++11 в языке появилась возможность определять лямбда-выражения, для которых, в случае, если у Вас всего один return оператор, можно не указывать тип возвращаемого значения — компилятор может вывести его самостоятельно. Многие были удивлены тем, что такая возможность отсутствует для обычных функций. Соответствующее предложение было внесено еще до выхода С++11, однако его отложили из-за ограничений по времени, и вот теперь, спустя несколько лет, его добавили в стандарт. Так же, данная поправка говорит о том, что если функция или лямбда-выражение имеют несколько операторов return, возвращающих один и тот же тип, то в данном случае, компилятор тоже должен выводить значение типа автоматически, включая случай с рекурсивным вызовом.

auto iterate(int len)    // возвращаемое значение - int {   for (int i = 0; i < len; ++i)     if (search (i))       return i;   return -1; }  auto h() { return h(); } // ошибка, тип возвращаемого значения не известен  auto sum(int i) {   if (i == 1)     return i;           // возвращаемое значение - int   else     return sum(i-1)+i;     // теперь можно вызывать рекурсивно }  template <class T> auto f(T t) { return t; } // тип будет выведен во время инстанцирования   []()->auto& { return f(); }                  // возврат ссылки 

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

// foo.h class Foo { public:   auto getA() const; };  // foo.cpp #include "foo.h"  auto Foo::getA() const {   return something; }  // main.cpp #include "foo.h"  int main() {   Foo bar;   auto a = bar.getA(); // ошибка, невозможно вывести тип } 

А значит использовать это получится только с локальными функциями или с функциями, определенными в заголовочных файлах. К последним, как правило, относятся шаблонные функции — основное, на мой взгляд, применение для данной новинки.
К ограничениям, определенным в стандарте, относятся: запрет на использование с виртуальными функциями и запрет на возврат объекта типа std::initializer_list.

Обобщенная инициализация захваченных переменных лямбд с поддержкой захвата-по-перемещению

В С++11 лямбды не поддерживают захват-по-перемещению (capture-by-move). Например, следующий код не будет скомпилирован:

#include <memory> #include <iostream> #include <utility>  template <class T> void run(T&& runnable) {   runnable(); };  int main() {   std::unique_ptr<int> result(new int{42});   run([result](){std::cout << *result << std::endl;}); } 

Чтобы переместить объект внутрь лямбда функции, необходимо было написать какую-нибудь обертку, наподобие устаревшего auto_ptr.
Вместо того, чтобы добавить возможность явного захвата-по-перемещению, было принято решение добавить поддержку обобщенной инициализации захваченные переменных. Например,

[ x { move(x) }, y = transform(y, z), foo, bar, baz ] { ... }  

В данном случае, x будет напрямую инициализирован перемещением x, y будет инициализирован результатом вызова transform, а остальные будут захвачены по значению. Другой пример:

int x = 4; auto y = [&r = x, x = x+1]()->int {             r += 2;             return x+2;          }();  // Обновляет ::x до 6, и инициализирует y 7-кой. 

Не запрещено и явное указание типа инициализируемых захваченных переменных:

[int x = get_x()] { ... }  [Container y{get_container()}] { ... } [int z = 5] { ... } 

У многих может возникнуть вопрос, почему просто не поддерживать следующий способ:

[&&x] { ... }  

Проблема в том, что мы не захватываем по rvalue ссылке, мы пытаемся переместить. Если бы мы пошли таким способом, то перемещение могло бы произойти гораздо позже, когда реальный объект уже может не существовать. Мы должны перемещать объект во время захвата переменных, а не во время вызова лямбды.

Обобщенные (полиморфные) лямбда-выражения

В С++11 лямбда выражения создают объекты класса, имеющего нешаблонный оператор вызова функции. Данная поправка предлагает:

  • Позволить использовать auto тип-спецификатор, означающий обобщенный (шаблонный) лямбда параметр
  • Позволить преобразование из лямбда функции, не захватыющей значения, к соответствующему указателю-на-функцию

Таким образом, одна и та же шаблонная лямбда может использоваться в разных контекстах:

void f1(int (*)(int))   { } void f2(char (*)(int))  { }   void g(int (*)(int))    { }  // #1 void g(char (*)(char))  { }  // #2   void h(int (*)(int))    { }   // #3 void h(char (*)(int))   { }   // #4   auto glambda = [](auto a) { return a; }; f1(glambda);  // OK f2(glambda);  // ошибка: ID не конвертируем g(glambda);   // ошибка: двусмысленно h(glambda);   // OK: вызывает #3, так как может быть сконвертировано из ID int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK 

Не забываем про возможность использования вместе с универсальными ссылками и шаблонами переменного количества аргументов (variadic templates):

auto vglambda = [](auto printer) {    return [=](auto&& ... ts) {   // OK: ts - это упакованные параметры функции        printer(std::forward<decltype(ts)>(ts)...);    }; }; auto p = vglambda( [](auto v1, auto v2, auto v3)                            { std::cout << v1 << v2 << v3; } ); p(1, 'a', 3.14);  // OK: выводит 1a3.14 

Упрощенные ограничения на создание constexpr функций

Внесенные изменения позволяют в constexpr функциях использовать:

  • Объявление переменных (за исключением static, thread_local и неинициализированных переменных)
  • if и switch (но не goto)
  • for (включая range-based for), while и do-while
  • Изменение состояния объектов, являющихся результатом constexpr вычислений

constexpr int abs(int x) {   if (x < 0)     x = -x;   return x;                     // OK }  constexpr int first(int n) {   static int value = n;         // ошибка: статическая переменная   return value; }  constexpr int uninit() {   int a;                        // ошибка: неинициализированная переменная   return a; }  constexpr int prev(int x)   { return --x; }               // OK  constexpr int g(int x, int n) { // OK   int r = 1;   while (--n > 0) r *= x;   return r; } 

В дополнение, было удалено правило, по которому constexpr нестатические функции-члены неявно получали const спецификатор (подробнее об этом здесь).

Шаблоны переменных

Данная возможность позволяет создавать и использовать constexpr шаблоны переменных, для более удобного сочетания с шаблонными алгоритмами (возможно использование не только со встроенными типами, но и с типами, определенными пользователем):

template<typename T> constexpr T pi = T(3.1415926535897932385);  template<typename T> T circular_area(T r) {   return pi<T> * r * r; }  struct matrix_constants {   template<typename T>   using pauli = hermitian_matrix<T, 2>;    template<typename T>   constexpr pauli<T> sigma1 = { { 0, 1 }, { 1, 0 } };    template<typename T>   constexpr pauli<T> sigma2 = { { 0, -1i }, { 1i, 0 } };    template<typename T>   constexpr pauli<T> sigma3 = { { 1, 0 }, { -1, 0 } }; }; 

Изменения в стандартной библиотеке

exchange

Атомные (atomic) объекты предоставляют atomic_exchange функцию, которая позволяет назначить объекту новое значение и вернуть его старое значение. Подобная функция может быть полезна и для обычных объектов.

// вероятная реализация template<typename T, typename U=T> T exchange(T& obj, U&& new_val) {   T old_val = std::move(obj);   obj = std::forward<U>(new_val);   return old_val; } 

Для притивных типов эта функция делает тоже самое, что и обычная реализация. Для сложных типов эта функция позволяет:

  • Избежать копирования старого объекта, если для этого типа определен конструктор перемещения
  • Принимать любое тип в качестве нового значения, получая преимущество использования любого конвертирующего оператора присваивания
  • Избежать копирования нового объекта, если он временный или был перемещен сюда

Например, реализация std::unique_ptr::release:

template<typename T, typename D> void unique_ptr<T, D>::reset(pointer p = pointer()) {   pointer old = ptr_;   ptr_ = p;   if (old)     deleter_(old); } 

может быть улучшена до:

template<typename T, typename D> void unique_ptr<T, D>::reset(pointer p = pointer()) {   if (pointer old = std::exchange(ptr_, p))     deleter_(old); } 

make_unique

В С++11, вместе с умными указателями, появилась и такая функция, как make_shared. Она позволяет оптимизировать выделение памяти для shared_ptr, а так же повысить безопасность относительно исключений. И хотя аналогичная оптимизация для unique_ptr невозможна, то повышенная безопасность относительно исключений никогда не повредит. Например здесь, в обоих случаях, мы можем получить утечку памяти, если при создании одного объекта бросилось исключение, а второй объект уже создан, но еще не помещен в unique_ptr:

void foo(std::unique_ptr<A> a, std::unique_ptr<B> b);  int main() {   foo(new A, new B);   foo(std::unique_ptr<A>{new A}, foo(std::unique_ptr<B>{new B}); } 

Чтобы решить эту ситуацию, было решено добавить функцию make_unique. Таким образом С++14 практически полностью (за исключение очень редких случаев) предлагает программистам отказаться от операторов new и delete.
Пример использования:

#include <iostream> #include <string> #include <memory> using namespace std;  void foo(std::unique_ptr<string> a, std::unique_ptr<string> b) {}  int main() {     cout << *make_unique<int>() << endl;     cout << *make_unique<int>(1729) << endl;     cout << "\"" << *make_unique<string>() << "\"" << endl;     cout << "\"" << *make_unique<string>("meow") << "\"" << endl;     cout << "\"" << *make_unique<string>(6, 'z') << "\"" << endl;      auto up = make_unique<int[]>(5);      for (int i = 0; i < 5; ++i) {         cout << up[i] << " ";     }      cout << endl;      foo(make_unique<string>(), make_unique<string>()); // утечка памяти невозможна      auto up1 = make_unique<string[]>("error"); // ошибка     auto up2 = make_unique<int[]>(10, 20, 30, 40); // ошибка     auto up3 = make_unique<int[5]>(); // ошибка     auto up4 = make_unique<int[5]>(11, 22, 33, 44, 55); // ошибка } /* Output: 0 1729 "" "meow" "zzzzzz" 0 0 0 0 0 */ 

Обособленные строки

При использовании строк, включающих в себя пробел, с потоками ввода/вывода, можно получить далеко не всегда ожидаемые результаты. Например:

std::stringstream ss; std::string original = "foolish me"; std::string round_trip;  ss << original; ss >> round_trip;  std::cout << original;   // вывод: foolish me std::cout << round_trip; // вывод: foolish  assert(original == round_trip); // assert сработает 

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

std::stringstream ss; std::string original = "foolish me"; std::string round_trip;  ss << quoted(original); ss >> quoted(round_trip);  std::cout << original;     // вывод: foolish me std::cout << round_trip;   // вывод: foolish me  assert(original == round_trip); // assert не сработает 

Если строка уже содержит кавычки в себе, они будут так же обособлены:

std::cout << "She said \"Hi!\";  // вывод: She said "Hi!" std::cout << quoted("She said \"Hi!\"");  // вывод: "She said \"Hi!\"" 

Данная поправка основана на boost аналоге.

Пользовательские литералы для типов стандартной библиотеки

C++11 вводит понятие пользовательских литералов (ПЛ), но ни одного ПЛ не было определенно для стандартной библиотеки, хотя согласно стандарту, имена ПЛ начинающиеся не с символа нижнего подчеркивания, зарезервированы за STL.
Соответствующая поправка добавляет в стандарт следующие пользовательские литералы:

  • Оператор s для basic_string
  • Операторы h, min, s, ms, us, ns для типов, входящих в chrono::duration

Например:

auto mystring = "hello world"s;   // тип std::string   auto mytime = 42ns;               // тип chrono::nanoseconds 

Пользовательские литералы s не конфликтуют, поскольку они принимают разные типы параметров.

optional

Данная поправка вводит в стандартную библиотеку новый тип, означающий необязательный объект. Возможный способы использования:

  • Возможность указать, какие параметры функций необязательны
  • Возможность использовать null-состояние (без использования обычных (raw) указателей)
  • Возможность ручного контроля времени жизни RAII объектов
  • Возможность пропустить дорогие (стандартные) конструкторы объектов

Примерный способ использования:

optional<int> str2int(string);    // приводит строку к целому числу, если возможно   int get_int_form_user() {   string s;     for (;;) {     cin >> s;     optional<int> o = str2int(s); // 'o' может содержать целое число, а может и нет     if (o) {                      // содержит ли 'o' целое число?       return *o;                  // используем число     }   } } 

Данная поправка основана на boost аналоге.
Перевод статьи автора этой поправки об этом классе можно найти здесь.

shared_mutex и shared_lock

При разработке многопоточных программ иногда появляется необходимость дать к некоторому объекту множественный доступ на чтение или уникальный доступ на запись. Данная поправка добавляет в стандартную библиотеку shared_mutex, предназначенный для этой цели. Функция lock дает уникальный доступ, и может быть использона с добавленными ранее lock_guard и unique_lock. Чтобы получить совместный доступ, необходимо использовать lock_shared функцию, и лучше это делать через добавленый RAII класс shared_lock:

using namespace std; shared_mutex rwmutex; {   shared_lock<shared_mutex> read_lock(rwmutex);   // чтение } {   unique_lock<shared_mutex> write_lock(rwmutex); // или lock_guard   // запись } 

Стоит отметить, что стоимость любого лока, даже на чтение, дороже, чем при использовании обычного мьютекса.
Данная поправка основана на boost аналоге.

dynarray

В текущем стандарте С есть динамические массивы, размер которых может быть определен только во время выполнения. Как и у обычных массивов, данные у них создаются на стэке. С++14 утверждает такие массивы, но при этом определяет еще и свой собственный вид динамический массив — std::dynarray, который так же узнает свой размер во время выполнения и не может изменять его в дальнейшем, однако может либо расположить объекты на стэке, либо разместить их в куче, при этом имея интерфейс во многом схожий с std::array и std::vector. Согласно поправке, этот класс может быть явно оптимизирован компилятором, для случаев использования стэка.

Заключение

В основном, С++14 позиционируется, как minor bug-fix release, исправляя недостатки С++11, допущенные из-за ограничений по времени или по каким-либо другим причинам. Текущий черновик стандарта С++ можно найти здесь.

ссылка на оригинал статьи http://habrahabr.ru/post/184606/

Избавляемся от строковых констант в Objective-C

Магические константы в коде — зло. Строковые константы в коде — еще большее зло.
И вроде бы от них никуда не денешься, они повсюду:

1) При загрузке объектов из xib-ов:

MyView* view = [[[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil] lastObject];

MyViewController* controller = [MyViewController initWithNibName:@"MyViewController" bundle:nil];

2) При работе с CoreData:

NSFetchRequest *request = [[NSFetchRequest alloc] init]; [request setEntity:[NSEntityDescription entityForName:@"MyCoreDataClass" inManagedObjectContext:moc]]; [request setSortDescriptors:@[ [[NSSortDescriptor alloc] initWithKey:@"someProperty" ascending:NO] ]];

3) Если вы используете KVO, то строки появляются и тут:

[self addObserver:someObservedObject         forKeyPath:@"someProperty"           options:(NSKeyValueObservingOptionNew |  NSKeyValueObservingOptionOld)            context:nil];

4) Ну и KVC:

NSInteger maxValue = [[arrayOfMyClassObjects valueForKeyPath:@"@max.someProperty"] intValue];

5) Но даже если CoreData вы предпочитаете работу с SQLite напраямую, xib-ами вы брезгуете, то вот такой код вам должен быть знаком:

[self.tableView dequeueReusableCellWithIdentifier:@"MyTableViewCell"];

6) Ну и когда Apple представила миру Storyboard — это было замечательно, если-бы не одно но:

[self performSegueWithIdentifier:@"MySegue" sender:nil]

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:( id )sender {    if ( [segue.identifier isEqual:@"MySegue"] ); }

Вы видите проблему? Она состоит в том, что компилятор никак не проверяет содержимое строк, поскольку не знает (да и не может в принципе знать), что в них содержится. И если вы опечатаетесь или измените значение соответствующих полей в xcdatamodel / xib / storyboard / переименуете property, то ошибка вылезет не на стадии компиляции, а в рантайме, и отловить и исправить ее будет дольше и дороже.
Так что-же можно сделать?
С некоторыми строками можно справиться административными мерами, с некоторыми — при помощи специального инструментария.

Загрузка из xib-ов

Например, если начать с правила, что имя xib-а должно совпадать с именем класса, который он содержит, то код из первого примера можно переписать так:

MyView* view = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([MyView class]) owner:self options:nil] lastObject];

MyViewController* controller = [MyViewController initWithNibName:NSStringFromClass([MyViewController class] bundle:nil];

Плюсом такого решения будет то, что если мы надумаем переименовать наш класс ( Xcode -> Edit -> Refactor -> Rename оставив галочку «Rename related files» выбранной ), то его при переименоввании xib будет так-же переименован, и, соответственно, загрузка вью/контроллера никак не пострадает.

CoreData

С примером 2 решение чуть сложнее и комплекснее.
Для начала нам понадобятся MagicalRecord и mogenerator

Если вы работаете с CoreData и все еще не используете эти замечательные инструмменты, то самое время начать.
Добавим MagicalRecord в наш podfile (ну или по старинке скопировав файлы в проект — за подробностями в гихаб)

pod MagicalRecord

И установим mogenerator:

brew install mogenerator

Или скачаем установщик с сайта и поставим его вручную.

mogenerator создает на основе файла модели CoreData исходные файлы, которые иначе пришлось бы писать руками.
Теперь нам нужно настроить проект так, чтобы запускать утилиту при каждой сборке.
Project -> Targets -> Add Build Phase -> Add Run Script:
Идем в настройки таргета, в закладку Build Phases и добавляем новую фазу в виде скрипта:
image
Ну и сам скрипт:
image
На одном уровне с нашей моделью нужно создать две папки Human и Machine. Жмем CMD+B — после чего добавляем эти две папки в проект. Они будут содержать в себе сгенерированные файлы модели из CoreData.

KVO и KVC

Еще одна вещь в Objective-C, которая активно использует строковые константы — KeyPath для KVO и KVC. Можно использовать упомянутый выше mogenerator. Если у нас в модели есть класс MyCoreDataClass, то mogenerator создаст структуры MyCoreDataClassAttributes, MyCoreDataClassRelationships и MyCoreDataClassFetchedProperties. Так что теперь можно переписать пример № 2 так:

NSArray* arr = [MyCoreDataClass MR_findAllSortedBy:MyCoreDataClassAttributes.someProperty ascending:NO inContext:moc];

А пример № 3 так:

[self addObserver:myCoreDataClass        forKeyPath:MyCoreDataClassAttributes.someProperty           options:(NSKeyValueObservingOptionNew |  NSKeyValueObservingOptionOld)            context:nil];

Но такое решение подойдет только для CoreData. Нам же нужно что-то более общее.

Для этого вполне подойдет библиотека Valid-KeyPath:

#import "EXTKeyPathCoding.h"  [self addObserver:myClass        forKeyPath:KEY.__(MyClass, someProperty)           options:(NSKeyValueObservingOptionNew |  NSKeyValueObservingOptionOld)            context:nil];

Либо EXTKeyPathCoding библотеки libextobjc:

pod libextobjc

#import "MTKValidKeyPath.h"  [self addObserver:myClass        forKeyPath:@keypath(MyClass.new, someProperty)           options:(NSKeyValueObservingOptionNew |  NSKeyValueObservingOptionOld)            context:nil];

Плюсами обоих решений будет autocompletion из IDE во время написания самого кода, а также проверка самого KeyPath на стадии компиляции.

Если вы используете KVC, как в примере 4, то для генерации KeyPath вы можете воспользоваться любой из библиотек, представленных выше, а можете — любой из LINQ-like библиотек для Objective-C, например LinqToObjectiveC

pod LinqToObjectiveC

NSInteger maxValue = [arrayOfMyClassObjects aggregate:^(MyClass* myClass, NSInteger aggregate){    return MAX( [myClass.someProperty intValue],  aggregate); }];
Storyboard

Что касается UI части, то тут нам поможет утилита ssgenerator Скачиваем ее отсюда
Создаем для нее еще один скрипт в проекте:
image
После чего добавляем в проект сгенерированные файлы StoryboardSegue.h и StoryboardSegue.m. В этих файлах содержатся категории для тех контроллеров в сториборде, которые содержат в себе UIStoryboardSegue или UITableViewCell, для которых определены идентификаторы. Теперь можно использовать:

[self.tableView dequeueReusableCellWithIdentifier:self.cells.MyTableViewCell];

[self performSegueWithIdentifier:self.segue.MySegue sender:nil]

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:( id )sender {    if ( [segue.identifier isEqual:self.segue.MySegue] ); }

Заключение

Избавление от строковых констант в коде — не самоцель, а способ существенно сэкономить на написании и поддержке кода за счет проверок во время компиляции. Часть описанных способов требует сторонних утилит, часть — сторонних библиотек. Для некоторых программистов описанные методики покажутся «сложными» и «плохочитаемыми», но все они направлены на как можно раннее выявление ошибок в коде. Так что если вы пишете код, который не изменяется, код, в котором нет ошибок — эти способы не для вас.

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

ссылка на оригинал статьи http://habrahabr.ru/post/184394/

Сборка Qt 5.1 приложений под Android на Mac, seriously?

image
Привет, QHabr.

Сегодня хотел бы рассказать вам про адъ, который кроется за сборкой Qt 5.1 приложения для андрюши на Mac OS X. Чтобы никто их хабралюдей ни в коем случае не попал туда на 7-8 часов, я решил сделать подробный step-by-step гайд. Ну что, приступим к делу.

Совсем недавно, Qt Project анонсировал Qt 5.1 RC1. Это пока достаточно рабочий свежак, но с неплохими нововведениями. Одно из них — поддержка кросс-компиляции Android. Замечательно, не так ли? Они даже любязно предоставили нам сборку кьюта под android… для Linux. Но как же быть тем, кто использует Mac, или куда более ущербный Windows для разработки? А ничего, собирайте сами.

Но сборка последнего Qt из Git, с нужными параметрами под маком, не говоря о Windows — это адъ. Сегодня я помогу вам спасти свои души!

Шаг 1. Подготавливаем систему

На данный момент в PATH должны лежать:

  • Git >= 1.6
  • Perl >= 5.14
  • Python >= 2.6
  • Самый последний XCode с его Command Line Tools
  • Последний Android SDK
  • Последний Android NDK
  • Могучая горсть терпения

Может быть, я что-то пропустил, но все же мы продолжаем.

Шаг 2. Получение и конфигурация Qt

Сейчас открываем консольку, переходим в удобную вам пустую папку и выполняем:

git clone git://gitorious.org/qt/qt5.git qt5 cd qt5 

Теперь пора сконфигурировать нашу локальную версию:

perl init-repository --no-webkit # вебкит зачастую никому не нужен, к тому же эта жирная скотина долго собирается 

А теперь самое сложное — конфигурация. Я использовал такие ключи:

./configure -prefix <installation directory> -release -shared -opensource -nomake examples -nomake tests -nomake tools -confirm-license -developer-build -xplatform android-g++ -android-ndk <android ndk root path> -android-sdk <android sdk root path> -android-ndk-host darwin-x86_64 -skip qttranslations -skip qtserialport 

Поздравляю, товарищи! Локальная копия Qt from Git сконфигурирована!

Шаг 3. Сборка Qt from Git

Тут все куда интереснее — нужно задать несколько переменных окружения (у меня такие пути):

export JAVA_HOME=/Library/Java/Home export ANDROID_HOME=/usr/local/Android/sdk export ANDROID_NDK_ROOT=/usr/local/Android/ndk export ANDROID_NDK_HOST=darwin-x86_64 export ANDROID_NDK_PLATFORM=android-17 export ANDROID_NDK=/usr/local/Android/ndk export MAKE=/usr/bin/make 

Кстати, на момент написания статьи актуальным API является android-17. И да, на этом наши настройки не заканчиваются! В Qt Multimedia есть баг, который сейчас нужно фиксить вручную. Проверьте мой багрепорт — если он все еще не решен, то вам стоит заглянуть под спойлер.

Временный фикс бага

Давайте откроем любым удобным вам текстовым редактором файл jar.pri и изменяем содержимое 4 строчки на:

API_VERSION = $$ANDROID_NDK_PLATFORM # кстати, это правильно? просто я ставил android-17 сразу, но думаю что так правильнее 

Теперь стоит собрать и установить Qt 5.1 выполнением комманд

make make install 

Шаг 4. Нам нужен последний Qt Creator

Возвращаемся в папку, где мы выполняли git clone (в самом начале статьи) и делаем следующее:

git clone git://gitorious.org/qt-creator/qt-creator.git qtc cd qtc qmake # кумейк нормального десктопного кьюта make 

Запускаем его и уходим в Preferences -> Android. Настраивам пути и создаем Android Virtual Device.

Теперь переходим в Compilers и мы должны увидеть примерно такую картину (у меня немного больше компиляторов вроде как должно быть):

Наступил черед Qt Version, заходим и создаем Qt for Android, указывая путь на qmake в папке установки кьюта, которого мы сегодня собрали

И под чечетку и фанфары модифицируем, уже созданный автоматически Kit

Шаг 5. Собираем приложение!

Создаем обычное Qt GUI приложение, задаем Kit — Qt 5.1 Android, или как он у вас там называется. Работаем в пределах MainWindow и нажимаем Command+R.

image

image

image

image

image

image

Скорее всего вам придется пошаманить с настройками деплоя

image

и манифестом приложения

image

Послесловие

Habrahabr::Reader *reader = this->reader(); reader->thankYou(); 

ссылка на оригинал статьи http://habrahabr.ru/post/185140/