Pull to refresh
0
0
Send message
Я вот тоже знаком с автором лично и специально уточнил у него: «Сатирой это назвать сложно.»
Антипример — С++. Впоследствии разработчики языков стали учитывать ошибки С++, и например C# гораздо лучше парсится «на лету».

Проблема парсинга C++ не столько в том, что его парсить долго, сколько в том, что его парсить много:
$ cat hw.cpp
#include <iostream>
int main() { std::cout << "Hello, World!\n"; }

$ g++ -std=c++11 -E hw.cpp | wc
  24304   53850  597619
Там, где другие распарсили бы 2 строчки, компилятор C++ парсит почти 0.6 Мб.
Для простого случая gcc выдаёт практически идентичный код.
#include <boost/range/irange.hpp>

void do_the_thing(int);

void oldschool(int a, int b)
{
    for (auto i = a; i < b; ++i)
        do_the_thing(i);
}

void ranges(int a, int b)
{
    for (auto i : boost::irange(a, b))
        do_the_thing(i);
}

$ g++-4.9.2 -std=c++14 -O3 -DNDEBUG -c range.cpp

$ objdump -dC range.o 
range.o:     формат файла elf64-x86-64


Дизассемблирование раздела .text:

0000000000000000 <oldschool(int, int)>:
   0:   55                      push   %rbp
   1:   53                      push   %rbx
   2:   89 f5                   mov    %esi,%ebp
   4:   89 fb                   mov    %edi,%ebx
   6:   48 83 ec 08             sub    $0x8,%rsp
   a:   39 f7                   cmp    %esi,%edi
   c:   7d 10                   jge    1e <oldschool(int, int)+0x1e>
   e:   66 90                   xchg   %ax,%ax
  10:   89 df                   mov    %ebx,%edi
  12:   83 c3 01                add    $0x1,%ebx
  15:   e8 00 00 00 00          callq  1a <oldschool(int, int)+0x1a>
  1a:   39 eb                   cmp    %ebp,%ebx
  1c:   75 f2                   jne    10 <oldschool(int, int)+0x10>
  1e:   48 83 c4 08             add    $0x8,%rsp
  22:   5b                      pop    %rbx
  23:   5d                      pop    %rbp
  24:   c3                      retq   
  25:   66 66 2e 0f 1f 84 00    data32 nopw %cs:0x0(%rax,%rax,1)
  2c:   00 00 00 00 

0000000000000030 <ranges(int, int)>:
  30:   55                      push   %rbp
  31:   53                      push   %rbx
  32:   89 f5                   mov    %esi,%ebp
  34:   89 fb                   mov    %edi,%ebx
  36:   48 83 ec 08             sub    $0x8,%rsp
  3a:   39 f7                   cmp    %esi,%edi
  3c:   74 10                   je     4e <ranges(int, int)+0x1e>
  3e:   66 90                   xchg   %ax,%ax
  40:   89 df                   mov    %ebx,%edi
  42:   83 c3 01                add    $0x1,%ebx
  45:   e8 00 00 00 00          callq  4a <ranges(int, int)+0x1a>
  4a:   39 dd                   cmp    %ebx,%ebp
  4c:   75 f2                   jne    40 <ranges(int, int)+0x10>
  4e:   48 83 c4 08             add    $0x8,%rsp
  52:   5b                      pop    %rbx
  53:   5d                      pop    %rbp
  54:   c3                      retq   


Насчет сложных случаев не уверен, можно ли сочинить такой, что gcc решит это всё не инлайнить.
Перечитал статью внимательнее. Судя по симптомам и лечению, действительно (был) единственный.

ISO IEC 14882-2003 §12.8 Copying class objects [class.copy]
A member function template is never instantiated to perform the copy of a class object to an object of its class type.

Сноска:
106) Because a template constructor is never a copy constructor, the presence of such a template does not suppress the implicit declaration of a copy constructor. Template constructors participate in overload resolution with other constructors, including copy constructors, and a template constructor may be used to copy an object if it provides a better match than other constructors.


ISO IEC 14882-2011 §12.8 Copying class objects [class.copy]
A member function template is never instantiated to produce such a constructor signature.


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

Т.е. нужно явно определять конструктор копирования, что вы в итоге и сделали, но это не «some magic cases», а так и задумано.

А copy-elision тут ни в чём не виновен.
    template<typename T_OtherType,
            typename T_OtherHolding,
            typename T_OtherAccess>
    DReference(
            const DReference<T_OtherType, T_OtherHolding, T_OtherAccess> &
                    inLReference) : _holder(NULL), _holding(), _access()
    {
        retain(inLReference._holder);
    }


Это единственный конструктор, предназначеный для копирования DReference?
Вписывается:

svn.boost.org/trac/boost/wiki/BoostEvo

However, it is ultimately the decision of the library developer which versions of C++ to support and how.

New libraries will not be rejected because they lack support for older platforms, particularly if new language or library features are integral to the library interface or design. An example would be a library that cannot provide a usable interface without use of a new C++ feature.

GCC 4.5.3
B::B()
B::B(const B&)
B::B(const B&)
B::~B()
B::~B()
B::~B()

GCC 4.6.3
B::B()
B::B(const B&)
B::B(B&&)
B::~B()
B::~B()
B::~B()

GCC 4.7.2
B::B()
B::B(const B&)
B::B(B&&)
B::~B()
B::~B()
B::~B()

Про precompiled headers + cmake можно посмотреть тут: www.cmake.org/Bug/view.php?id=1260.
http://www.artima.com/cppsource/type_erasure.html?

Также можно взглянуть на Boost.TypeErasure, который недавно приняли в состав.

Ещё на эту тему есть тут: http://www.youtube.com/watch?v=_BpMYeUFXv8.
Т.е. %home% вместо $HOME или ~ вас не смущает?
Это смотря как считать :)
По вашей просьбе размещаю и здесь:
осторожно, много текста
Давайте попробуем искать не первый/последний из эквивалентных элементов, а границы содержащего их интервала.

Интервал будет полуоткрытый справа, т.е. [lower_bound, upper_bound) как и все используемые интервалы. В случае, если искомого элемента нет, интервал будет пустой и обе границы (у пустого интервала границы равны) будут указывать на «место для вставки».

Для определения как отсортирована последовательность используем компаратор.
Будем считать, что компаратор comp в нашей последовательности выполняет роль оператора < и элементы в ней отсортированы по возрастанию (возрастанию относительно компаратора).
Т.е. если у нас последовательность целых чисел отсортирована по убыванию, то компаратором в ней будет оператор >. Если у нас последовательность пар чисел, отсортированных по величине второго числа… ну вы поняли о чем я.

lower_bound — позиция первого элемента, который не меньше искомого.
upper_bound — позиция первого элемента, который больше искомого.

Я буду использовать не индексы, а итераторы т.к. считаю, что в данной постановке задачи они уместнее (а ещё потому, что я это буду делать на C++ «в стиле STL»).

Попробуем найти lower_bound:

template<typename FwdIter, typename T, typename Comp>
FwdIter lower_bound(FwdIter first, FwdIter last, T const& x, Comp comp)
{
    // если интервал пустой, то его и возвращаем
    if (first == last)
        return first;
    
    // вычислим позицию среднего элемента
    FwdIter middle = first;
    std::advance(middle, std::distance(first, last) / 2);
    
    // Если средний элемент меньше искомого, т.е. искомый больше среднего элемента,
    // то т.к. последовательность отсортирована по возрастанию,
    // искомый элемент должен находиться справа от среднего, иначе — слева
    if (comp(*middle, x))
        return lower_bound(++middle, last, x, comp);
    else
        return lower_bound(first, middle, x, comp);
}


upper_bound можно выразить через lower_bound:
У нас есть оператор <, а нам нужен ≤.
Выразим одно через другое:
a ≤ b ⇔ !(b < a)

template<typename FwdIter, typename T, typename Comp>
FwdIter upper_bound(FwdIter first, FwdIter last, T const& x, Comp comp)
{
    typedef typename std::iterator_traits<FwdIter>::value_type value_type;
    
    auto less_equal = [&comp](value_type const& a, T const& b){return !comp(b, a);};
    
    return lower_bound(first,last, x, less_equal);
}


Варианты для компаратора по умолчанию пишутся тривиально.

Ну и осталась обертка для проверки входит ли элемент в последовательность и на какой позиции.

template<typename FwdIter, typename T, typename Comp>
FwdIter binary_search(FwdIter first, FwdIter last, T const& x, Comp comp)
{
    FwdIter found = lower_bound(first, last, x, comp);
   
    // Если элемент не найден, found может оказаться равен правой границе.
    // Если found указывает на существующий элемент, то он не меньше искомого.
    // Т.е. *found или больше или равен x, если больше, то x не нашелся.
    if (found == last || comp(x, *found))
    {
        // Элемент не найден.
        // Вернем верхнюю границу диапазона в качестве индикатора.
        return last;
    }
   
    return found;
}


Последняя обертка, не даёт информацию о месте вставки, если элемент не нашелся, однако никто не запрещает воспользоваться lower_bound напрямую, если мы собираемся вставлять элемент.

За исключеним нескольких нюансов, мы практически переизобрели соответствующие алгоритмы из STL:
lower_bound
upper_bound
binary_search
equal_range

Тщательно не тестировал, но вроде работает.
Тут автор излагает эту идею на чуть более конкретных вещах: http://www.youtube.com/watch?v=WpkDN78P884.
Добавил в тест BOOST_FOREACH.

Linux 32bit, gcc 4.6.3, Qt 4.8.1

"New for" results(ms): avg:100 min:97 max:108
"Accumulate" results(ms): avg:100 min:97 max:108
"Qt foreach" results(ms): avg:103 min:100 max:112
"Boost foreach" results(ms): avg:101 min:97 max:106
"STL for" results(ms): avg:130 min:126 max:151
"STL for 2" results(ms): avg:99 min:97 max:104

Run test for type: FSt6vectorIiSaIiEEvE
"New for" results(ms): avg:100 min:97 max:106
"Accumulate" results(ms): avg:98 min:95 max:104
"Qt foreach" results(ms): avg:258 min:249 max:290
"Boost foreach" results(ms): avg:100 min:97 max:107
"STL for" results(ms): avg:100 min:98 max:107
"STL for 2" results(ms): avg:99 min:97 max:108

Run test for type: F5QListIiEvE
"New for" results(ms): avg:100 min:98 max:110
"Accumulate" results(ms): avg:101 min:98 max:106
"Qt foreach" results(ms): avg:103 min:101 max:111
"Boost foreach" results(ms): avg:100 min:98 max:108
"STL for" results(ms): avg:131 min:126 max:146
"STL for 2" results(ms): avg:101 min:98 max:110
Надо нашему начальнику отдела качества и директорам дать это почитать. Ато ведь так и будет «ладно, на станции доделаем как всегда».
*посмотреть его
Тогда уж лучше increaseSpeed(double speed_meters_per_sec), ато ещё спросят как вы в миллисекундах скорость измеряете.

А вообще идея статьи взята из выступления Страуструпа на GoingNative2012 (но примеры и реализация как-то неудачно обрезаны), лучше посмотреть, если ещё не.
Он(майнкрафт) как чистый лист бумаги: если тебе есть что сказать — ты пишешь, если же нет, то сам по себе этот лист бумаги тебя не развеселит, в этом наверное и заключается главный минус данной игры.
© откуда-то из интернета

Information

Rating
Does not participate
Registered
Activity