Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

C++

Войти
Регистрация
Восстановить пароль
Результаты опроса: Почему вы избегаете использовать С++11 ?
еще не дошел до изучения. 23 37.10%
а зачем мне оно? 13 20.97%
мой компилятор не поддерживает. 18 29.03%
а что это? оО 11 17.74%
Опрос с выбором нескольких вариантов ответа. Голосовавшие: 62. Вы ещё не голосовали в этом опросе

 
 
Рейтинг: Рейтинг темы: голосов - 81, средняя оценка - 4.65
niXman
Эксперт С++
3138 / 1450 / 49
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
#1

Почему вы избегаете использовать возможности С++11 ? - C++

13.01.2012, 12:08. Просмотров 11017. Ответов 123
Метки нет (Все метки)

всем привет.

сабж.

я-то, в полную использую. везде где только могу.
но частенько вижу вопросы типа: "а без использования С++0х нельзя?"
любопытна аргументация.

благодарен.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
13.01.2012, 12:08
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Почему вы избегаете использовать возможности С++11 ? (C++):

Почему нельзя использовать более одной TServerSocket? - C++ Builder
Пробовал использовать в программе две компоненты TserverSocket и не получилось. Выдает ошибку: «Обычно разрешается одно использование...

Почему следует избегать явного приведения типов? (по возможности) - C++
Почему следует избегать явного приведения типов? (по возможности)

Почему не получается использовать bitset в VC++? - C++
Никак не получается использовать bitset в VC++6 . Очень надо - двоичный вектор . В стандарте описан bitset , но работать отказывается ....

Почему не рекомендуется использовать препроцессор? - C++
Я сейчас активно пользуюсь #define для упрощения понимания кода. Например, у меня сложная система классов, что бы получить одну...

Почему break нельзя использовать в if? - C++
почему break нельзя использовать в if вот код if(f.eof()==1) { break; } про break MVS говорит что ОПЕРАТОР break...

Почему плохо использовать unsigned int? - C++
Почему плохо использовать unsigned int и чему он удобней для представления массивов бит чеm signed int? (Из Страуструпа)

123
hoggy
6672 / 2856 / 491
Регистрация: 15.11.2014
Сообщений: 6,369
Завершенные тесты: 1
24.07.2016, 11:31 #61
Цитата Сообщение от vxg Посмотреть сообщение
Применение новшеств ради них самих
как насчет:
ради удобств, простоты, и принципиально новых возможностей?
0
vxg
Модератор
3172 / 1975 / 222
Регистрация: 13.01.2012
Сообщений: 7,605
24.07.2016, 11:45 #62
hoggy, если в этом есть обоснованная необходимость безусловно необходимо применять все доступные в языке новшества для решения задачи. Мне такие чудные задачи видимо не попадались. И мне почему-то кажется что таких задач на самом деле нет)
0
hoggy
6672 / 2856 / 491
Регистрация: 15.11.2014
Сообщений: 6,369
Завершенные тесты: 1
24.07.2016, 11:50 #63
Цитата Сообщение от vxg Посмотреть сообщение
если в этом есть обоснованная необходимость безусловно необходимо применять все доступные в языке новшества для решения задачи. Мне такие чудные задачи видимо не попадались. И мне почему-то кажется что таких задач на самом деле нет)
все нововведения в стандарт языка (в core-language, а так же - в стандартную библиотеку)
были продиктованы необходимостью.

и потом, простота, удобства, и принципиально новые возможности,
это не каприз программистов.
это - прямая выгода для компаний,
выраженная сокращением времени на разработку,
снижением затрат на сопровождение не актуальных велосипедов,
и ускорение разработки за счет более удобных,
и простых средств языка.
0
vxg
Модератор
3172 / 1975 / 222
Регистрация: 13.01.2012
Сообщений: 7,605
24.07.2016, 12:05 #64
hoggy, знаете, даже в C98 "въезжают" в достаточном объёме ограниченное число разработчиков, а стандарты выше него привносят в язык настолько инопланетные конструкции, что его в целом наверное не понимают даже в комитете (ситуация схожая с состоянием дел в физике частиц - все понимают ядерные реакции, но все эти кварки... струны... и прочая "кислота" - её понимает лишь пара человек - остальные смотрят на них как на идиотов) - и вы говорите что была привнесена простота и легкость понимания и сопровождения? Хм. По мне - так это выглядит как игры разума Эйнштейнов которые там гибкость мозгов тренируют - яснее вещи которые и так были ясными яснее не стали. ИМХО: две ложки здравого смысла, две бочки мозговых пируэтов (можно посмотреть как на балет, но сложнее - повторить) и два вагона маркетинга.
0
hoggy
6672 / 2856 / 491
Регистрация: 15.11.2014
Сообщений: 6,369
Завершенные тесты: 1
24.07.2016, 12:15 #65
Цитата Сообщение от vxg Посмотреть сообщение
знаете, даже в C98 "въезжают" в достаточном объёме ограниченное число разработчиков
нет. не знаю.

я понимаю, Москва не сразу строилась.
и что б стать миддлом, нужно сначала пройти этап джуна.

однако, однажды джун научится.
и я не знаю ни одного миддла,
который не умел бы с++11 в достаточном объёме.
не говоря уже о прошлых стандартах.

Цитата Сообщение от vxg Посмотреть сообщение
а стандарты выше него привносят в язык настолько инопланетные конструкции, что его в целом наверное не понимают даже в комитете
не знаю ни одной такой конструкции.
приведите пример.

на практике я вижу лишь,
с++1y привнес новшества,
которые упростили во многом синтаксические конструкции.

например:
auto, decltype, вариадики, rvalue-reference - значительно упростили метапрограммирование,
и позволили колоссально сократить объемы кода.
я уже молчу про то, что сегодня стало возможным создание таких механизмов,
которые раньше были в принципе не возможны.
0
vxg
Модератор
3172 / 1975 / 222
Регистрация: 13.01.2012
Сообщений: 7,605
24.07.2016, 13:15 #66
hoggy
Приятно слышать что в этом мире есть люди понимающие C++
Удивительно слышать что эти люди считают что их знание абсолютно
Относительно примеров - к сожалению я не практикую сравнительный анализ стандартов поэтому могу лишь "выкрикивать с места" различные реплики которые и так должны быть известны и приняты к сведению всеми кто знакомился с 11-м. Из того что приходило мне в голову когда я пробегал глазами: лично для меня ценность такого приобретения как auto спорна - человек должен знать что он объявляет, а не просить "эй ну объяви ну как там её ну эту ну ты сам знаешь". Это ОЧЕНЬ коротко с этим не поспоришь, но что-то меня в этом тревожит. Знаете, так и снятся кошмары, что я объявляю итератор, а его тип не совпадает с ожидаемым (то есть я думаю там скажем rec_type , а там rec_type_2 и у них обоих одноименные поля и я не догадываюсь что работаю не совсем с тем с чем думаю). Фобия)
0
hoggy
6672 / 2856 / 491
Регистрация: 15.11.2014
Сообщений: 6,369
Завершенные тесты: 1
24.07.2016, 13:40 #67
Цитата Сообщение от vxg Посмотреть сообщение
человек должен знать что он объявляет
времени написания кода, программист в любом случае знает что он там объявляет.

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

Цитата Сообщение от vxg Посмотреть сообщение
а не просить "эй ну объяви ну как там её ну эту ну ты сам знаешь"
почему бы и нет?
очень удобный подход.

Цитата Сообщение от vxg Посмотреть сообщение
Фобия
хз, чего тут можно бояться.
в случае каких то изменений оно и так, и сяк покажет ошибки компиляции.
которые будут устранены за несколько минут.

ну или не покажет вовсе,
но опять таки - случится может в обоих случаях с одинаковым успехом.
0
vxg
Модератор
3172 / 1975 / 222
Регистрация: 13.01.2012
Сообщений: 7,605
24.07.2016, 13:45 #68
Цитата Сообщение от hoggy Посмотреть сообщение
очень удобный подход
да, очевидность этого я признаю
Цитата Сообщение от hoggy Посмотреть сообщение
программист в любом случае знает что он там объявляет
ну да, и ошибки у нас не смотря на то что сборка прошла успешно появляются просто потому что нам так захотелось
0
hoggy
6672 / 2856 / 491
Регистрация: 15.11.2014
Сообщений: 6,369
Завершенные тесты: 1
24.07.2016, 13:50 #69
Цитата Сообщение от vxg Посмотреть сообщение
ну да, и ошибки у нас не смотря на то что сборка прошла успешно появляются просто потому что нам так захотелось
ошибки были, есть и будут.

но есть хорошая новость:
чем проще код, и чем его меньше, и чем удобнее инструмент,
тем ниже вероятность их появления.
0
silent_1991
Эксперт С++
4984 / 3041 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
24.07.2016, 14:15 #70
Цитата Сообщение от vxg Посмотреть сообщение
Почти не встречал вещей которые нельзя выразить на C98.
Почти не встречал вещей, которые невозможно выразить в машинных кодах.
Цитата Сообщение от vxg Посмотреть сообщение
Конечно, хорошо когда можно писать тоже самое, но короче.
Только для этого и появляются новые языки программирования или новые версии существующих. Чтобы те же вещи можно было сделать быстрее/проще/более производительно. А иначе все до сих пор писали бы на "см. комментарий к предыдущей цитате".
Цитата Сообщение от vxg Посмотреть сообщение
Хорошо когда в std увековечены разные полезные вещи которые раньше лежали в других библиотеках.
ИМХО это самое бесполезное, чем занимается комитет (и чем, к сожалению, он в основном и занимается, если судить по 17 стандарту) - перетаскивает буст в стандарт.
Цитата Сообщение от vxg Посмотреть сообщение
Применение новшеств ради них самих, ради бряцания кодом, по религиозным соображениям и т.п. приводящее к потере обратной совместимости = преступление.
Преступление - это попытка сохранить пресловутую обратную совместимость всеми правдами и неправдами. И по итогам этого преступления мы имеем (самый яркий пример, который первым приходит в голову) убогие макросытекстовые подстановки вместо нормальных синтаксических гигиенических макросов и убогие инклюды вместо нормальных человеческих модулей.
Цитата Сообщение от vxg Посмотреть сообщение
hoggy, если в этом есть обоснованная необходимость безусловно необходимо применять все доступные в языке новшества для решения задачи. Мне такие чудные задачи видимо не попадались. И мне почему-то кажется что таких задач на самом деле нет)
И снова см. ответ 1. Любую задачу можно решить множеством разных способов. Можно писать в машинных кодах. Можно писать на асме. Можно писатьдумать, что пишешь на C98, при этом запихнув весь код в функцию main и растянув её на 5к строк кода и называть все переменные одной буквой, а вместо циклов использовать goto. Язык лишь предоставляет инструментарий. Программист пользуется им в силу своих знаний, умений и изобретательности.
Цитата Сообщение от vxg Посмотреть сообщение
знаете, даже в C98 "въезжают" в достаточном объёме ограниченное число разработчиков, а стандарты выше него привносят в язык настолько инопланетные конструкции
В целом, согласен. Язык, по моему мнению, из стандарта в стандарт безбожно усложняют. Но в ворохе усложнений попадаются действительно интересные вещи, которые позволяют писать более простой (лямбды, foreach, variadic templates, автовывод типов), производительный (move-семантика, обязательный copy elision в 17 стандарте) и безопасный (смарт-поинтеры и соотвествующие make-функции, final/override) код.
Цитата Сообщение от vxg Посмотреть сообщение
что его в целом наверное не понимают даже в комитете
Странное предположение.
Цитата Сообщение от vxg Посмотреть сообщение
лично для меня ценность такого приобретения как auto спорна - человек должен знать что он объявляет, а не просить "эй ну объяви ну как там её ну эту ну ты сам знаешь".
Указание типа - мета-информация для программиста. Компилятору оно не нужно, он и так знает, какой тип должен быть в объявлении слева, на основании выражения справа. Мне
C++
1
auto iter = std::begin(container);
нравится куда больше, чем
C++
1
std::map<std::string, std::vector<std::pair<std::string, int>>>::iterator_type iter = container.begin();
Я уже один раз запарился и указал тип при объявлении container. Зачем меня заставлять делать это снова и снова?
Цитата Сообщение от vxg Посмотреть сообщение
но что-то меня в этом тревожит. Знаете, так и снятся кошмары, что я объявляю итератор, а его тип не совпадает с ожидаемым
Ну что ж, как известно, всё новое и неизвестное сначала пугает. Но вы не бойтесь. Вас никто не заставляет писать auto везде и всегда. Да и не получится это, где-то тип должен быть объявлен явным образом и исчерпывающе. А auto поможет не стирать пальцы в кровь, объявляя его снова и снова, как я показал выше.
0
vxg
Модератор
3172 / 1975 / 222
Регистрация: 13.01.2012
Сообщений: 7,605
24.07.2016, 15:40 #71
silent_1991, упрощение из упрощений - PHP - пишите на нем там даже auto не нужен) шутка. если у вас есть лишние 30 минут не могли бы вы кодом проиллюстрировать самые прекрасные нововведения? foreach мне понятно по аналогии. auto уже обсуждался, а остальное - что за заклинания?
0
silent_1991
Эксперт С++
4984 / 3041 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
24.07.2016, 20:04 #72
Продемонстрирую то, что я перечислил. Приступим.

1. Лямбда-функции (замыкания).
Предположим, нужно подсчитать количество элементов в векторе, удовлетворяющих заданному критерию (пусть это будут чётные числа).
Раньше:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <algorithm>
#include <iostream>
#include <vector>
 
class EvenNumberPredicate {
public:
    bool operator()(int number) const
    {
        return number % 2 == 0;
    }
};
 
int main()
{
    std::vector<int> vec;
    vec.push_back(7);
    vec.push_back(2);
    vec.push_back(3);
    vec.push_back(8);
    vec.push_back(4);
    vec.push_back(1);
    std::cout << std::count_if(vec.begin(), vec.end(), EvenNumberPredicate()) << std::endl;
    return 0;
}
Теперь (здесь я продемонстрировал ещё одно удобное введение 11 стандарта - списки инициализации, реализуемые библиотечным классом std::initializer_list; теперь так можно инициализировать не только скалярные массивы и структуры, но и любые кастомные классы, или даже передавать их в функции как аргумент):
C++
1
2
3
4
5
6
7
8
9
10
#include <algorithm>
#include <iostream>
#include <vector>
 
int main()
{
    std::vector<int> vec = { 7, 2, 3, 8, 4, 1 };
    std::cout << std::count_if(vec.begin(), vec.end(), [](int n) { return n % 2 == 0; }) << std::endl;
    return 0;
}
2. foreach (покажу для полноты).
Просто обходим словарь и печатаем элементы в виде "key: value".
Раньше:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <map>
 
int main() {
    std::map<std::string, std::string> map;
    map["one"] = "first";
    map["two"] = "second";
    map["three"] = "third";
    map["four"] = "fourth";
    for (std::map<std::string, std::string>::const_iterator it = map.begin(); it != map.end(); ++it) {
        std::cout << it->first << ": " << it->second << std::endl;
    }
    return 0;
}
Теперь (тут и auto заодно применяется, что говорит о согласованности нововведений):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <map>
 
int main() {
    std::map<std::string, std::string> map = {
        { "one",   "first"  },
        { "two",   "second" },
        { "three", "third"  },
        { "four",  "fourth" },
    };
    for (const auto& it : map) {
        std::cout << it.first << ": " << it.second << std::endl;
    }
    return 0;
}
3. Variadic templates.
Честно говоря, мне лень самому писать примеры, тем более, что простые примеры получатся синтетическими и, таким образом, довольно неубедительными. Вот статья, где показаны примеры использования таких шаблонов (правда, там они тоже синтетические, но там есть код). Стоит сказать, что раньше, до появления этого в стандарте, подобное по-человечески провернуть было буквально невозможно. Теперь, при наличии шаблонов с переменным числом параметров, появилась возможность, например, реализовать действительно типобезопасный форматный ввод-вывод (scanf/printf), или же благодаря этой возможности реализуются такие функции как std::make_shared и std::make_unique (см. ниже).

4. Move-семантика и rvalue-ссылки.
Позволяет подсказать компилятору, как именно перемещать содержимое объекта в случае, когда полноценно копировать его нет необходимости. Например:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <algorithm>
#include <cstdint>
#include <initializer_list>
#include <iostream>
 
template<typename T>
class Array {
public:
    Array(std::size_t size):
        m_buf(new T[size]),
        m_size(size)
    {
        std::cout << "Array::Array(std::size_t)" << std::endl;
    }
    
    Array(const std::initializer_list<T>& init):
        m_buf(new T[init.size()]),
        m_size(init.size())
    {
        std::cout << "Array::Array(const std::initializer_list<T>&)" << std::endl;
        std::copy(std::begin(init), std::end(init), m_buf);
    }
    
    Array(const Array& other):
        m_buf(new T[other.m_size]),
        m_size(other.m_size)
    {
        std::cout << "Array::Array(const Array&)" << std::endl;
        std::copy(other.m_buf, other.m_buf + other.m_size, m_buf);
    }
    
    Array(Array&& other):
        m_buf(other.m_buf),
        m_size(other.m_size)
    {
        std::cout << "Array::Array(Array&&)" << std::endl;
        // Важно! Если этого не сделать, вызов деструктора на other сделает
        // невалидным конструируемый объект
        other.m_buf = nullptr;
    }
    
    ~Array()
    {
        delete[] m_buf;
    }
    
    Array& operator=(const Array& other)
    {
        std::cout << "Array::operator=(const Array&)" << std::endl;
        
        if (this != &other)
        {
            delete[] m_buf;
            m_buf = new T[other.m_size];
            m_size = other.m_size;
            std::copy(other.m_buf, other.m_buf + other.m_size, m_buf);
        }
        
        return *this;
    }
    
    Array& operator=(Array&& other)
    {
        std::cout << "Array::operator=(Array&&)" << std::endl;
        m_buf = other.m_buf;
        m_size = other.m_size;
        // Важно! Если этого не сделать, вызов деструктора на other сделает
        // невалидным конструируемый объект
        other.m_buf = nullptr;
        return *this;
    }
    
private:
    T *m_buf;
    std::size_t m_size;
};
 
int main() {
    Array<int> a1 = { 1, 2, 3, 4, 5 };
    Array<int> a2 = { 6, 7, 8 };
    Array<int> a3 = a1;
    Array<int> a4 = std::move(a2); // a2 невалиден после этой строки
    a1 = a3;
    a2 = std::move(a4); // a4 невалиден после этой строки
    return 0;
}
На самом деле, это простой искусственный пример. std::move здесь используется, чтобы показать, в каких случаях какой конструктор/оператор будет вызван. std::move просто превращает переданное ей значение в rvalue-ссылку (Type&&). Но инициировать вызов соответствующего оператора/конструктора можно неявно. Например, если из функции возвращается объект по значению, то в стандартной ситуации будет вызван конструктор копирования (временный объект, возвращённый из функции, будет скопирован в новое место, а затем разрушен), а если это присваивание, а не инициализация, то ещё и оператор присваивания (второе копирование). (Стоит сказать, что здесь может вступить в игру copy elision - оптимизация копирования временных объектов - но до 17 стандарта, который ещё не вышел, не определено, когда и как должна делаться эта оптимизация, так что компиляторы вольны решать это самостоятельно.) При наличии move-семантики он будет перемещён (в случае приведённого кода будет скопирован указатель на буфер, новых выделений памяти не будет).
Кроме того, rvalue-ссылки позволили реализовать такую вещь как perfect forwarding, но это тема отдельного разговора. Если интересно, поищите в гугле по этому словосочетанию.
5. Smart pointers
Не поверю, что вы о них не слышали) Сами умные указатели перетащили из буста (с некоторыми изменениями-улучшениями, насколько я знаю), но благодаря perfect forwarding и variadic templates можно полностью избежать явных вызовов оператора new (что, бесспорно, великолепно; сам умный указатель скрывает в себе вызов delete, а теперь код будет свободен ещё и от явных new; управление ресурсами становится всё проще). Т.е. если у нас есть класс Foo, имеющий такой конструктор:
C++
1
Foo::Foo(int, double, char);
и нам нужно положить его экземпляр в shared_ptr, мы можем написать так:
C++
1
auto ptr = std::make_shared<Foo>(42, 3.14, 'a');
И здесь нет никакой магии. std::make_shared - шаблонная функция, параметром шаблона которой является список типов переменной длины. Принимает она список значений соответствующих типов. Список значений, который приняла функция, можно распаковать при помощи оператора '...'. Соответственно, реализация её может выглядеть примерно так:
C++
1
2
3
4
5
template<typename T, typename... Args>
std::shared_ptr<T> make_shared(Args&&... args)
{
    return std::shared_ptr<T>(new T(args...));
}
new никуда не исчез, он просто сокрыт внутри библиотечной функции. Зато он исчез из пользовательского кода. Теперь можно писать на C++, сохраняя все его преимущества, но при этом не управляя ресурсами вручную.

6. final/override
Тут всё просто, добавили возможность явно выразить намерение переопределить виртуальную функцию базового класса (ключевое слово overrdie) либо наоборот, запретить переопределять виртуальную функцию в производном классе или вообще наследовать от самого класса (ключевое слово final).
Чем полезен overide? Тем, что он гарантирует, что будет функция будет именно переопределена, т.е. будет производиться проверка сигнатуры. Например:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
 
class Foo {
public:
    virtual void method() const
    {
        std::cout << "Foo::method()" << std::endl;
    }
};
 
class Bar : public Foo {
public:
    virtual void method()
    {
        std::cout << "Bar::method()" << std::endl;
    }
};
 
int main() {
    Bar b;
    Foo& f = b;
    b.method();
    f.method();
    return 0;
}
Мы намеревались переопределить method базового класса Foo в производном Bar. Но мы забыли указать const в сигнатуре, и произошло не переопределение, а перекрытие. Упс... Результат совсем не тот, что мы ожидали.
А теперь так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
 
class Foo {
public:
    virtual void method() const
    {
        std::cout << "Foo::method()" << std::endl;
    }
};
 
class Bar : public Foo {
public:
    virtual void method() override
    {
        std::cout << "Bar::method()" << std::endl;
    }
};
 
int main() {
    Bar b;
    Foo& f = b;
    b.method();
    f.method();
    return 0;
}
Другое дело, теперь нас ожидает ошибка компиляции. Мы сказали, что переопределяем, но в базовом классе нет функции с такой сигнатурой, так что компилятор бьёт нас по рукам. Фиксим:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
 
class Foo {
public:
    virtual void method() const
    {
        std::cout << "Foo::method()" << std::endl;
    }
};
 
class Bar : public Foo {
public:
    virtual void method() const override
    {
        std::cout << "Bar::method()" << std::endl;
    }
};
 
int main() {
    Bar b;
    Foo& f = b;
    b.method();
    f.method();
    return 0;
}
Вот теперь код делает то, что мы ожидали.
Чем полезем final? Например, как известно, классы стандартной библиотеки не помечают свои деструкторы виртуальными. Таким образом, наследовать от них небезопасно. Пока мы выделяем объекты на стеке - всё в порядке. Но как только мы начинаем выделять их в куче, а потом, например, пытаться работать с ними (в том числе, удалить их посредством оператора delete/delete[]) через указатель на базовый класс - начинаются проблемы. При попытке удаления память спокойно может утечь в неизвестном направлении. Будь возможность пометить такие классы как ненаследуемые - проблем бы не было. Теперь такая возможность имеется.

Фух, всё это заняло отнюдь не 30 минут.
Вообще, если вы попробуете отбросить скептицизм и даже, в какой-то степени, упрямство, советую почитать последнюю книгу Мейерса "Эффективный и современный C++". Там описаны все фишки 11 и 14 стандартов, и куда лучше, чем я их тут попытался объяснить. Всё подробно, аргументированно, почему так лучше, чем сяк, и с примерами.
2
hoggy
6672 / 2856 / 491
Регистрация: 15.11.2014
Сообщений: 6,369
Завершенные тесты: 1
24.07.2016, 20:17 #73
Цитата Сообщение от silent_1991 Посмотреть сообщение
template<typename T, typename... Args>
std::shared_ptr<T> make_shared(Args&&... args)
{
return std::shared_ptr<T>(new T(args...));
}
одна из киллер-фичь с++11 - благодаря вариадикам и r-value-reference
стала возможной оптимальная стратегия передачи аргументов.
что было в принципе не возможно во времена с++03

только это нужно правильно уметь готовить:

C++
1
2
3
4
std::shared_ptr<T> make_shared(Args&&... args)
{
    return std::shared_ptr<T>(new T(  std::forward<Args>(args)... ));
}
иначе будут прострелы конструкторов копий, вместо мува.
1
silent_1991
Эксперт С++
4984 / 3041 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
24.07.2016, 20:37 #74
hoggy, да, спасибо за поправку. Сам же про perfect forwarding написал - и сам же о нём благополучно забыл
0
Убежденный
Системный программист
Эксперт С++
15689 / 7199 / 1137
Регистрация: 02.05.2013
Сообщений: 11,634
Записей в блоге: 1
Завершенные тесты: 1
24.07.2016, 22:57 #75
Почему вы избегаете использовать С++11 ?
У меня специфика работы такова, что задачи, которые приходится решать,
лежат далеко за пределами языкового уровня. Упрощенно говоря, от всяких
там полиморфных лямбд и улучшенных SFINAE мне не жарко, ни холодно; важна в
первую очередь идея, т.е. некое инженерно-техническое решение, а язык -
всего лишь инструмент, который позволяет воплотить эту идею в жизнь.
Содержание преобладает над формой. Я и из C++98/03 использую далеко не
все возможности, лишь самое необходимое и простое.

Другая причина в том, что работа с новым C++ требует новых версий
Visual Studio, а это означает отказ от Windows XP и, например, от "древних"
процессоров, у которых нет поддержки определенных команд типа SSE2.

Нет, я понимаю, что кроме MS C++ Compiler есть еще Clang, GCC, Intel, и
даже иногда "балуюсь" на онлайн-компиляторах и почитываю всякие proposal,
еще не включенные в стандарт, но на работе, в моих текущих реалиях, где
все очень сильно завязано на стек технологий Microsoft и их инструментарий,
на поддержку обратной совместимости, такие вещи или малополезны или
вообще неприменимы.

Как мне кажется, наибольшую выгоду от C++11 и выше получают разработчики
всевозможных библиотек с шаблонами и метапрограммированием - Boost,
STLSoft и т.п., а "прикладникам" хватает и того, что есть в C++98.
2
24.07.2016, 22:57
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
24.07.2016, 22:57
Привет! Вот еще темы с ответами:

Почему не стоит использовать ^(XOR) в swap - C++
Прочитал статейку, http://betterexplained.com/articles/swap-two-variables-using-xor/ Что-то не до понял, почему нельзя...

Почему clear необходимо использовать до seekg? - C++
...и нельзя сразу после? Долго не могла решить проблему пока не наткнулась на тему где f.clear() шел до f.seekg(). И мне стало интересно))...

Пояснить, почему в примере не рекомендуется использовать закрытое наследование - C++
Всем доброго времени суток ! Помогите пожалуйста разобраться с этой фразой на примере . То что я знаю про закрытое наследование ,...

Почему программа в Windows может использовать лишь 1792 мегабайта RAM? - C++
Простейшая программа, для того чтобы узнать сколько памяти можно использовать в системе. int main() { unsigned int...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
75
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru