-2

Как мне узнать количество char-ов которые выделены с помощью new??

bloody
  • 98
  • 6
  • конкретезируйте вопрос пожалуйста – Eikthyrnir Mar 23 '22 at 20:25
  • 1
    Никак нельзя, хранить отдельно. – HolyBlackCat Mar 23 '22 at 20:28
  • 2
    либо используйте с++ способ - std::string, std::vector<char> – KoVadim Mar 23 '22 at 20:54
  • 1
    man malloc_usable_size (или malloc_size в apple или _msize в винде) – avp Mar 23 '22 at 22:08
  • 1
    вот только это для malloc. Да, new/new[] под капотом может использовать malloc напрямую, а может и нет. Плюс нет абсолютно никакой гарантии, что тот указатель, который возвращает malloc, будет возвращает и с помощью new. – KoVadim Mar 24 '22 at 10:07
  • 1
    @KoVadim стандартный оператор new[] действительно внутри себя вызывает malloc() и если та возвращает NULL, бросает исключение. Более того, если выделяется массив классов, содержащих деструктор, то длина массива помещается перед возвращаемым оператором new[] указателем - т.е., сам указатель на такой массив смещается относительно выделенной области на 4 байта (во всяком случае в g++ так). Подзырено в дизассемблере)) – LShadow77 Mar 24 '22 at 17:20
  • 1
    насколько я знаю по опыту, gcc и vs по разному реализует поведение new[]/delete[]. Более того, студия в отладочном режиме оставляет достаточно информации, что бы понять, по указателю массив или просто один объект, а в релизе все достаточно чистенько и ничего лишнего. И да, оно вызывает malloc, но я не видел требования это делать. – KoVadim Mar 24 '22 at 18:06

1 Answers1

0

Насколько мне известно (но я могу ошибаться) не существует документированного способа узнать размер динамически выделенного массива по его указателю. Соответственно, возможны следующие варианты:

  1. Вместе с указателем на массив сохранять размер последнего в переменной. Например:

    char* pMyArray = new char[NUM_CHARS];

    int myArrayLen = NUM_CHARS;

  2. Следует из (1) - использовать класс-обёртку, представляющий пару "указатель на массив, размер массива". Например, в черновом варианте это может выглядеть так:

     template <typename T=char>
     class CDynamicArray
     {
         T* m_pData;
         int m_length;
    

    public: CDynamicArray() { m_pData = nullptr; }

     T* Create(int length)
     {
         m_pData = new T[length];
         m_length = length;
         return m_pData;
     }
    
     void Delete()
     {
         if (m_pData)
         {
             delete[] m_pData;
             m_pData = nullptr;
         }
     }
    
     T* GetData()
     {
         return m_pData;
     }
    
     int GetLength()
     {
         return m_length;
     }
    
     ~CDynamicArray()
     {
         Delete();
     }
    
     CDynamicArray(const CDynamicArray&amp;) = delete;
    

    };

  3. Не изобретать велосипед, а использовать уже готовое решение std::vector(https://en.cppreference.com/w/cpp/container/vector).

LShadow77
  • 2,157
  • 1
    ну хотя бы правило трех соблюли. А то до первого копирования – KoVadim Mar 24 '22 at 18:07
  • @KoVadim ну это же черновой вариант. Если не копировать, то вполне рабочий. – LShadow77 Mar 24 '22 at 18:39
  • Скажем так, это ужасный вариант. Вот функция create не нужна. Этим конструктор должен заниматься. А если эту функцию позовут дважды? В деструкторе лишний if и присваивание. – KoVadim Mar 24 '22 at 19:30
  • Да да, если не копировать этот код себе, то вполне нормально будет – KoVadim Mar 24 '22 at 19:47
  • @KoVadim конструктор-то этим может заниматься, однако тут есть один минус: вам не остаётся другого способа создать массив, кроме как при объявлении переменной класса, что бывает далеко не всегда удобно. Вариант с Create/Delete более гибкий (к тому же ничто не мешает добавить второй коструктор, вызывающий Create()). Насчёт вызова метода Create() дважды согласен, есть косяк - вариант же черновой. Исправляется с помощью if/assert. "Лишний if" в деструкторе погоды не делает, но от утечки памяти защищает. Хотя в своём коде для этой цели я использую assert, который никогда лишним не бывает)) – LShadow77 Mar 24 '22 at 20:57
  • от какой утечки защищает if в деструкторе? – KoVadim Mar 24 '22 at 21:02
  • @KoVadim если мы забыли вызвать метод Delete(), то деструктор его вызовет, и память будет освобождена. Если мы не забыли вызвать метод Delete(), то повторный его вызов в деструкторе погоды не сделает. – LShadow77 Mar 24 '22 at 21:06
  • @KoVadim а вообще в деструкторе можно разместить только assert (m_pData==nullptr); - в этом случае избегаем повторной проверки, однако метод Delete() придётся вызывать обязательно... – LShadow77 Mar 24 '22 at 21:11
  • 1
  • если m_pData == nullptr, тогда delete m_pData; работает нормально. Да, там ещё есть бяка. если позвать Create(...), потом Delete(), а потом GetLength(), то будет неожиданно. – KoVadim Mar 24 '22 at 21:21
  • @KoVadim а не надо звать Delete(), а потом GetLength(). Ну ёлки-палки, мой пример здесь передаёт только смысл! В допиленном до ума виде он раза в три больше будет и новичка может отпугнуть! – LShadow77 Mar 24 '22 at 21:29
  • @wololo благодарю)) – LShadow77 Mar 24 '22 at 21:31
  • @LShadow77 исправленный вариант занимает сильно меньше места. а "не нужно звать" - это неверный ответ. Если бы хотя бы зануляли размер... – KoVadim Mar 24 '22 at 21:40
  • @KoVadim я поленился занулить размер, ровно как написать конструктор копирования, вставить проверочные ассерты и директивы условной компиляции для проверки NDEBUG, добавить перегруженных операторов и методов для удобства в работе. Если исправленный вариант это std::vector, то тогда да, меньше места получится)) – LShadow77 Mar 24 '22 at 21:52