Форум программистов, компьютерный форум 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
155 / 147 / 58
Регистрация: 18.11.2015
Сообщений: 649
Завершенные тесты: 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>))
  • Компиляторы, по историческим причинам, произвели неудовлетворительные диагностики, когда был использован вышепоказанный код
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru