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

С++ идиомы - C++

Войти
Регистрация
Восстановить пароль
Другие темы раздела
C++ Внедрение DLL в EXE http://www.cyberforum.ru/cpp/thread1787895.html
Здравствуйте, хочу написать свой объединитель exe и dll. Подскажите, как это можно сделать так, чтобы можно было при запуске использовать dll без записи на диск
C++ Как создать оконную программу на c++ exe Можно по подробние как создать оконную программу на c++ exe . Я только что перешол на c++ из Bash (cmd , bat , командная строка ) и как то не хочется опять возвращатся к консольным программам . Я незнаю еще не каких команд для C++ и не знаю не каких компеляторов но хотелось бы создать хотяюы самую простую оконную программу без всяких функций что бы просто открылось пустое окно . Вы поможите ? И... http://www.cyberforum.ru/cpp/thread1787737.html
Парсинг журнала событий C++
возникла задача, получить некоторые данные из event log'a Windows, как это все реализовать ? с чего начать?
Не выделяется память C++
Здравствуйте, пытаюсь выделить память, на одном компьютере работает, на другом нет, возвращает 0x00000000, хотя память имеется в наличии. В чём может быть причина? size_t size = 1586753967; void* b = malloc(size); free(b); Добавлено через 6 минут errno = ENOMEM, хотя памяти доступно 4,2 ГБ Добавлено через 2 минуты
C++ Стек и куча http://www.cyberforum.ru/cpp/thread1786739.html
Вот говорят, что для стека доступного места меньше, чем для кучи. И если есть много переменных большого размера, то лучше создавать их через new. а почему так?
C++ Программа для отправки сообщения Привет всем. Может кто помочь? Задача следующая. Есть сервер, к которому подключается 10 человек. На этом сервере лежат 10 именных папок (по имени участника). Когда кто-то один из участников перекидывает со своей папки второму участнику, то в это время второму участнику должно автоматически прийти сообщение на почту, что "в такое время, такой участник перекинул вам файл." Как можно сделать... подробнее

Показать сообщение отдельно
meJevin
 Аватар для meJevin
154 / 146 / 57
Регистрация: 18.11.2015
Сообщений: 623
Завершенные тесты: 1
16.08.2016, 15:46     С++ идиомы
Nullptr

Задачи:
Научиться отличать число 0 от нулевого указателя


Мотивация:

На протяжении многих лет С++ имело позорный недостаток, у С++ не было ключевого слова, которое бы обозначало нулевой указатель. С++ 11 избавился от этого недостатка. Строгая типизация С++ делает определение глобальной константы NULL в стиле языка C почти что бесполезной в выражениях, например:
C++
1
2
3
4
5
6
7
8
9
10
// Если бы мы попробовали определить NULL в C++, вот так
#define NULL ((void *)0)
 
// То тогда...
 
char * str = NULL; // Ошибка: Нельзя автоматически привести тип void * к char *
 
void (C::*pmf) () = &C::func;
 
if (pmf == NULL) {} // Ошибка: Нельзя автоматически привести тип void * к типу указателя на функцию-член
В С++
C++
1
#define NULL 0
и
C++
1
#define NULL 0L
являются правильными (но не совсем) определениями константы нулевого указателя.

Проблема самого первого примера в том, что С++ запрещает приведение из типа void *, даже когда его значение является константным нулем. Но, для простого константного нуля С++ имеет преобразование int в указатель (еще short в указатель, long в указатель и т.п.).Это имеет свои минусы. Приведем пример на работе с перегруженными функциями:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
 
#define NULL 0
 
void func(int var) { std::cout << "Int" << std::endl; };
void func(double * ptr) { std::cout << "Double *" << std::endl; };
 
int main()
{
    func(static_cast <double *>(NULL)); // вызывается func(double *), как мы и хотели
 
    func(NULL); // запись интерпретируется, как func(0) - вызывается func(int).
                // но программист, скорее всего, хотел вызвать func(double *),
                // потому что NULL является константой нулевого УКАЗАТЕЛЯ,
                // которую мы определили ранее.
 
    return 0;
}
После обработки кода препроцессором, код в функции main превратиться в:
C++
1
2
3
4
5
func(static_cast <double *>(0));
 
func(0);
 
return 0;
После запуска этого кода, на экране будет:
Код
Double *
Int
Таким образом, чтобы использовать #define NULL 0 так, как задумывалось (с указателями), нужно всегда писать что типа static_cast<double *>(NULL)


Использование #define NULL 0 имеет свою кучку проблем. Помимо проблемы с перегруженными функциями, C++ требует того, чтобы NULL было определено целочисленным константным выражением со значением 0. Поэтому, в отличии от С, нулевой указатель не может быть определен как ((void *)0) в стандартной библиотеке C++. Более того, конкретная форма определения оставлена для той или иной реализации, что значит, что 0 и 0L - подходящие определения, наряду с некоторыми другими.



Решение и пример использования
Идиома нулевого указателя решает некоторые вышеперечисленные проблемы и может быть использована снова и снова. Будущий пример является очень близким по функционалу решением, относительно ключевого слова nullptr, добавленного в С++ 11, и использует только стандартные приемы, которые были доступны еще до С++ 11.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const // Объект константный...
class nullptr_t 
{
  public:
    template<class T>
    inline operator T*() const // Может быть приведен к любому типу нулевого указателя (не на член класса)
    { return 0; }
 
    template<class C, class T>
    inline operator T C::*() const   // или любому типу нулевого указателя на член
    { return 0; }
 
  private:
    void operator&() const;  // мы не можем взять адрес nullptr
 
} nullptr = {};
Код ниже показывает, как можно использовать класс, определенный выше (предполагается, что пользователь уже сделал #include класса выше)

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
#include <typeinfo>
//#include "nullptr_t"
struct C
{
    void func();
};
 
template<typename T>
void g(T* t) {}
 
template<typename T>
void h(T t) {}
 
void func(double *) {}
void func(int) {}
 
int main(void)
{
    char * ch = nullptr;        // Ок
    func(nullptr);             // Вызывает func(double *)
    func(0);                   // Вызывает func(int)
    void (C::*pmf2)() = 0;      // Ок
    void (C::*pmf)() = nullptr; // Ок
    nullptr_t n1, n2;
    n1 = n2;
    nullptr_t *null = &n1;    // Адрес мы взять не можем
    if (nullptr == ch) {}       // Ок
    if (nullptr == pmf) {}      // Это тоже работает, но не на g++ 4.1.1-4.5 из-за бага #33990
                                // для GCC 4: if ((typeof(pmf))nullptr == pmf) {}
    const int n = 0;
    if (nullptr == n) {}        // Не должно компилироваться, но только Comeau показывает ошибку
 
    int p = 0;
    if (nullptr == p) {}      // Не работает
    g (nullptr);              // Не возможно вывести тип T
 
    int expr = 0;
    char* ch3 = expr ? nullptr : nullptr; // ch3 - нулевой указатель
 
    char* ch4 = expr ? 0 : nullptr;     // ошибка, типы не совместимы
    int n3 = expr ? nullptr : nullptr;  // ошибка, нельзя преобразовать nullptr в int
    int n4 = expr ? 0 : nullptr;        // ошибка, типы не совместимы
 
    h(0);                // Выводит T = int
    h(nullptr);          // Выводит T = nullptr_t
    h((float*) nullptr); // Выводит T = float*
 
    sizeof(nullptr);     // Ок
    typeid(nullptr);     // Ок
    throw nullptr;       // Ок
}
К сожалению, похоже, есть баг в компиляторе gcc 4.1.1, который не распознает сравнение nullptr с указателем на функцию-член (pmf). Код выше успешно компилируется, если убрать строки с ошибками, которые мы допустили в демонстрационных целях (26, 31, 34, 35, 40, 41, 42, 50)

Заметьте, что идиома нулевого указателя использует идиому Return Type Resolver, чтобы автоматически вывести нулевой указатель правильного типа, в зависимости от типа объекта, к которому мы его присваиваем. Например, если nullptr присваивают к char *, создается функция преобразования с char параметром шаблона.


Последствия
Есть некоторые недостатки этого приема, в список этих недостатков входят следующие пункты:
  • Чтобы использовать nullptr, надо постоянно писать #include "nullptr_t". В С++ 11 и выше nullptr является ключевым словом и не требует включения заголовочного файла (но для использования std::nullptr_t заголовочный файл включать все равно надо (<cstddef>))
  • Компиляторы, по историческим причинам, произвели неудовлетворительные диагностики, когда был использован вышепоказанный код
 
Текущее время: 00:15. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru