Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Разыменование пустого указателя, который не пустой / 25 сообщений из 48, страница 1 из 2
24.10.2018, 16:27
    #39722294
Ciplusor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
Есть класс, который хранит размер и буфер описывающий в общем случае строку данных. После выделения буфера, сразу прописываю размер буфера, однако vs2017 выдает warning. Я так полагаю из за того, что конкретно для *m_buffer не выделяется память. Как правильно обойти этот варнинг?

Код: plaintext
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.
class string
{
private:
    char * m_Buffer = nullptr;
public:
    string() noexcept
    {
    }
    ~string()
    {
        free( m_Buffer);
    }
    bool Copy(const void * aBuffer, int aLength)
    {
        m_Buffer = (char*)malloc(sizeof(int) + aLength);

        * m_Buffer = aLength; // Разыменование пустого указателя "m_Buffer"

        return memcpy( m_Buffer + sizeof(int), aBuffer, aLength);
    }
    char * String()
    {
        return m_Buffer + sizeof(int);
    }
    int Length()
    {
        return * m_Buffer;
    }
};
...
Рейтинг: 0 / 0
24.10.2018, 16:43
    #39722306
NekZ
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
Ciplusor
Код: plaintext
1.
        * m_Buffer = aLength; // Разыменование пустого указателя "m_Buffer"


Ты разыменовываешь указатель на char и записываешь в него значение типа int. Это очень опасная дорожка.
Попробуй сначала преобразовать его к указателю на int и только потом разыменовывать.
...
Рейтинг: 0 / 0
24.10.2018, 16:50
    #39722317
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
NekZПопробуй сначала преобразовать его к указателю на int и только потом разыменовывать.

Не стоит. Ибо можно нарваться на забавные грабли с выравниванием и оптимизацией. Если
раскладка байт в буфере совпадает с платформой, то лучше пользоваться memcpy.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
24.10.2018, 16:53
    #39722323
NekZ
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
Dimitry SibiryakovНе стоит. Ибо можно нарваться на забавные грабли с выравниванием и оптимизацией. Если
раскладка байт в буфере совпадает с платформой, то лучше пользоваться memcpy.

Насчёт оптимизации согласен, а вот по поводу выравнивания не понял. Там же нет структуры. Или POD-типов это тоже касается?
...
Рейтинг: 0 / 0
24.10.2018, 17:01
    #39722332
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
NekZпо поводу выравнивания не понял

На высоких уровнях оптимизации компилятор может предполагать, что указатель на целое
выровнен правильно и превратить присваивание в один movd или аналогичную команду
процессора. Если это предположение неверно и команда не приспособлена работать с
невыровненной памятью - будет БУМ! В данном коде такого быть не может, но лучше не
привыкать к плохому.

И, кстати, я только сейчас обратил внимание, что аффтар-то пишет в буфер всего один байт,
а не всё целое. Хотя остаток кода предполагает иначе. И warning компилятора в данном
случае это указание на жосткого бага.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
24.10.2018, 20:45
    #39722478
OoCc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
CiplusorЕсть класс, который хранит размер и буфер описывающий в общем случае строку данных. После выделения буфера, сразу прописываю размер буфера, однако vs2017 выдает warning. Я так полагаю из за того, что конкретно для *m_buffer не выделяется память. Как правильно обойти этот варнинг?

и зачем делать через одно место когда можно сделать правильно? Достаточно сказать компилятору что ты хочешь.

Код: plaintext
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.
class string
{
    struct _s_l
    {
         size_t len;
         char  str[1];
    };

    _s_l  * m_Buffer;

public:
    string() noexcept
    {
        m_Buffer = static_cast<_s_l *>(malloc(sizeof(_s_l)));
        m_Buffer->len=0;
        m_Buffer->str[0] = '\0';
    }
    ~string()
    {
        free( m_Buffer);
    }
    bool Copy(const char * str)
    {
        free(m_Buffer);
        size_t l = strlen(str);
        m_Buffer = static_cast<_s_l *>(malloc(sizeof(_s_l) + l));

        m_Buffer->len = l; // и не нужно никакого разыменовывания
        m_Buffer->str[l] = '\0';
        return memcpy( m_Buffer->str, str, l);
    }
    char * String()
    {
        return m_Buffer->str;
    }
    size_t Length()
    {
        return m_Buffer->len;
    }
};
...
Рейтинг: 0 / 0
25.10.2018, 01:35
    #39722558
egorych
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
OoCcи зачем делать через одно место когда можно сделать правильно? Достаточно сказать компилятору что ты хочешь.а зачем извращаться с вложенной структурой, если в класс просто нужно добавить поле для длины?)) sizt_t m_Length, например ))
ну, и раз уж тут у нас C++, то фтопку malloc, нужно new[]
...
Рейтинг: 0 / 0
25.10.2018, 06:52
    #39722581
Ciplusor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
OoCcи зачем делать через одно место когда можно сделать правильно? Как вы можете судить о правильности, если не знаете предназначения? Моя строка - подготавливается для дальнейшей передачи через сокеты и в отличии от вашего случая - не выполняет лишних выделений памяти. Но это не суть важно.

авторИ, кстати, я только сейчас обратил внимание, что аффтар-то пишет в буфер всего один байт,
а не всё целоеХм, проверю, спасибо
...
Рейтинг: 0 / 0
25.10.2018, 07:11
    #39722585
Ciplusor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
Доработал по комментариям. Вышло обыденно и неинтересно. Но главное что работает и без варнингов, спасибо, не зря решил таки с ним разобраться :)

Код: plaintext
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.
class string
{
private:
    char * m_Buffer = nullptr;
    int m_offset = sizeof(int);
public:
    ~string()
    {
        delete[] m_Buffer;
    }
    bool Copy(const void * aBuffer, int aLength)
    {
        m_Buffer = new char[aLength + m_offset];
        return memcpy(m_Buffer, &aLength, m_offset)
            && memcpy(m_Buffer + m_offset, aBuffer, aLength);
    }
    char * String()
    {
        return m_Buffer + m_offset;
    }
    int Length()
    {
        return *m_Buffer;
    }
};

...
Рейтинг: 0 / 0
25.10.2018, 09:06
    #39722610
OoCc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
egorychа зачем извращаться с вложенной структурой, если в класс просто нужно добавить поле для длины?)) sizt_t m_Length, например ))
ну, и раз уж тут у нас C++, то фтопку malloc, нужно new[]
egorych ты неправ. ИМХО ТС хотел держать строку сериализованной с длинной. Вложенная структура это не изврещение - это описание сериализованного хранилища.
...
Рейтинг: 0 / 0
25.10.2018, 09:30
    #39722623
OoCc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
[quot Ciplusor] .... Моя строка - подготавливается для дальнейшей передачи через сокеты и в отличии от вашего случая - не выполняет лишних выделений памяти. Но это не суть важно.
...
Рейтинг: 0 / 0
25.10.2018, 13:58
    #39722822
ну я
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
Ciplusor
Код: plaintext
1.
2.
        * m_Buffer = aLength; // Разыменование пустого указателя "m_Buffer"
        return memcpy( m_Buffer + sizeof(int), aBuffer, aLength);


В первой строке прописывается значение типа char приведенное из int. Это нулевой байт. 1 штука.
Во второй строке что-то копируется после первых 4-х штук байт.
Тут как-бы предупреждение должно быть о неявном усечении int в char с возможной потерей информации
и как-бы что-то мусорное в первом, втором и третьем байтах с адреса m_Buffer.
Если по первому байту программа сможет определить что дальше 3 байта мусор - то как-бы но проблем.
А если нет...
...
Рейтинг: 0 / 0
25.10.2018, 17:19
    #39722970
blonduser
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
Ciplusor,

Вот так надо!

Код: plaintext
1.
 *(int*)m_Buffer = aLength; // Разыменование пустого указателя "m_Buffer"
...
Рейтинг: 0 / 0
25.10.2018, 17:47
    #39722987
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
Ciplusor,

структуры для описания буфера я так понимаю лучше не предлагать? только хардкор?

тынц
Код: plaintext
1.
2.
3.
4.
struct str_buffer{
   int len;
   char data[]; 
};
...
Рейтинг: 0 / 0
25.10.2018, 18:14
    #39723003
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
kealon(Ruslan)структуры для описания буфера я так понимаю лучше не предлагать? только хардкор?

Структуры это хорошо до тех пор пока не начинается обмен между платформами с разной
раскладкой байт.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
25.10.2018, 19:02
    #39723028
blonduser
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
kealon(Ruslan),
В структуре как раз и может случится выравнивание.
...
Рейтинг: 0 / 0
25.10.2018, 21:08
    #39723096
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
А еще malloc() может вернуть NULL
...
Рейтинг: 0 / 0
26.10.2018, 00:33
    #39723187
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
Dimitry Sibiryakovkealon(Ruslan)структуры для описания буфера я так понимаю лучше не предлагать? только хардкор?

Структуры это хорошо до тех пор пока не начинается обмен между платформами с разной
раскладкой байт.
там всё равно придётся переворачивать что пришло, и смысл париться с высчитыванием адресов?

с выравниванием тоже бороться можно

но создавать себе гемор на ровном месте...
...
Рейтинг: 0 / 0
26.10.2018, 05:35
    #39723218
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
CiplusorВышло обыденно и неинтересно.
А какова была цель хранения размера и контента в одном сплошном массиве?
...
Рейтинг: 0 / 0
26.10.2018, 09:35
    #39723286
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
CEMbCiplusorВышло обыденно и неинтересно.
А какова была цель хранения размера и контента в одном сплошном массиве?обычная практика для базовых классов, зачем два раза память выделять
...
Рейтинг: 0 / 0
26.10.2018, 11:53
    #39723382
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
kealon(Ruslan)обычная практика для базовых классов, зачем два раза память выделятьНууу... а почему два раза-то?
Вот:
kealon(Ruslan)
Код: plaintext
1.
2.
3.
4.
struct str_buffer{
   int len = 0;
   char *data = nullptr;
};

выделяешь один раз для data и тут же пишешь размер в len?
...
Рейтинг: 0 / 0
26.10.2018, 12:06
    #39723393
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
CEMbвыделяешь один раз для data и тут же пишешь размер в len?

А сам str_buffer выделяется автомагически? А в send() его придётся скармливать по частям?..
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
26.10.2018, 12:54
    #39723435
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
CEMb,

обычно ещё используют счётчики использования(refcount) что бы строки не дублировать при копировании объекта
...
Рейтинг: 0 / 0
26.10.2018, 16:59
    #39723682
Ciplusor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
kealon(Ruslan)CEMb,

обычно ещё используют счётчики использования(refcount) что бы строки не дублировать при копировании объектаЯ обошелся без ссылок, если идет присваивание - то исходная строка берется указателем, если нет - аллоцируется буффер. Позволяет использовать как с автодеструктором, так и с сохранением значения. Главное условие - снизить минимизацию работы с памятью. Возможно глупое решение, но на текущий момент меня устраивает вполне.
Код: plaintext
1.
string tmpName = tmpDb->ReadString("name")

Код: plaintext
1.
string * tmpPlayer->name = tmpDb->ReadString("name")

Код не претендует на оригинальность и возможно сплошной костыль, но я только начал изучать конструкторы копирования и перегрузку операторов присваивания :)
Код: plaintext
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.
class string
{
private:
    const string * m_Copy = nullptr;
    const int m_Offset = sizeof(int);
    char * m_Buffer = nullptr;
private: 
    void Assign(string * aString)
    {
        if (m_Copy)
            delete(m_Copy);
        m_Copy = aString;
    }
public:
    string()
    {

    }
    string(string * aString) noexcept
    {
        Assign(aString);
    }
    string(const void * aBuffer, int aLength)
    {
        m_Buffer = new char[aLength + m_Offset];
        if ((!memcpy(m_Buffer, &aLength, m_Offset))
            || (!memcpy(m_Buffer + m_Offset, aBuffer, aLength)))
            printf("Can't allocate string");
    }
    ~string()
    {
        if (m_Buffer)
            delete[] m_Buffer;
        if (m_Copy)
            delete(m_Copy);
    }
    char * String()
    {
        if (m_Copy)
            return m_Copy->m_Buffer + m_Copy->m_Offset;
        if (m_Buffer)
            return m_Buffer + m_Offset;
        printf("Not allocated string value");
        return nullptr;
    }
    int Length()
    {
        if (m_Copy)
            return *m_Copy->m_Buffer;
        if (m_Buffer)
            return *m_Buffer;
        printf("Not allocated string length");
        return 0;
    }
    string * operator = (string * aString)
    {
        Assign(aString);
        return this;
    }
};

...
Рейтинг: 0 / 0
29.10.2018, 05:15
    #39724223
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разыменование пустого указателя, который не пустой
Dimitry SibiryakovА сам str_buffer выделяется автомагически? А в send() его придётся скармливать по частям?..
Ну если на стеке, то автоматически, иначе динамически.
В send она должна сама себя скармливать, по-хорошему: наружу из класса торчат методы, которые знают, как работать с данными. Внешний код не должен знать и разбираться с внутренними структурами. Иначе, в случае, если вдруг между len и data добавили smth, то весь внешний код поедет.

Для меня сомнительна польза запихать всё в текстовый буфер ради send(). В том же случае, с добавлением smth в "структуру", мы получим больше проблем при обращении к "переменным".
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Разыменование пустого указателя, который не пустой / 25 сообщений из 48, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]