Управление памятью C++ и векторы

как @ john-saunders упомянул в своем ответе:

StringWriter всегда будет использовать UTF-16

, поэтому я использовал MemoryStream для этих целей.

В моем случае я использовал кодировку windows-1251.

var xmlSstring = "";
using (var ms = new MemoryStream())
{
    var encoding = Encoding.GetEncoding(1251);
    var settings = new XmlWriterSettings
    {
        Indent = true,
        Encoding = encoding
    };

    using (var xmlTextWriter = XmlWriter.Create(ms, settings))
    {
        doc.Save(xmlTextWriter);
        xmlString = encoding.GetString(ms.ToArray());
    }
}
5
задан Thomas L Holaday 8 June 2009 в 17:08
поделиться

8 ответов

I suspect your questions are about std::vector< T > (as opposed to an array T[]).

  1. When your application crashes or gets aborted for whatever reason, the OS reclaims the memory. If not you are using a truly rare OS and have discovered a bug.
  2. You need to distinguish between the memory used by the vector itself and the memory of its contained objects. The vector can be created on the heap or on the stack as you noted, the memory it allocates for its contained elements is always on the heap (unless you provide your own allocator which does something else). The memory allocated by the vector is managed by the implementation of vector, and if the vector is destructed (either because it goes out of scope for a vector on the stack or because you delete a vector on the heap) its destructor makes sure that all memory is freed.
16
ответ дан 18 December 2019 в 05:18
поделиться

Не используйте new для создания векторов. Просто положите их в стек.

Деструктор вектора автоматически вызывает деструктор каждого элемента в векторе. Так что вам не нужно беспокоиться об удалении объектов самостоятельно. Однако, если у вас есть вектор указателей, объекты, на которые ссылаются указатели, не будут очищены , а не . Вот пример кода. Для ясности я опускаю большинство деталей:

class HeapInt
{
    public:
        HeapInt(int i) {ptr = new int(i);}
        ~HeapInt() {delete ptr;}
        int& get() {return *ptr;}
    private:
        int* ptr;
};

int main()
{
    // this code DOES NOT leak memory
    std::vector<HeapInt> vec;
    for (int i = 0; i < 10; ++i)
    {
       HeapInt h(i);
       vec.push_back(h);
    }
    return 0;
}

Даже если main () выдает исключение, память не теряется. Однако этот код вызывает утечку памяти :

int main()
{
    // this code though, DOES leak memory
    std::vector<int*> vec;
    for (int i = 0; i < 10; ++i)
    {
       int* ptr = new int(i);
       vec.push_back(ptr);
    }
    // memory leak: we manually invoked new but did not manually invoke delete
    return 0;
}
10
ответ дан 18 December 2019 в 05:18
поделиться

Да, вы можете доверять векторам, которые убирают за собой.

ОДНАКО Нельзя доверять, что вектор материала очищает за собой. Что нужно очистить, может быть что-то, что сохраняется вне вашего приложения. Если это память, это не беспокойство. Если он следит за тем, чтобы все теги XML были закрыты, тогда ОС не сможет вам помочь.

Например, что, если у вас есть вектор некоторого шаткого объекта блокировки вроде этого:

  class CLock
  {
  public:
      CLock() {}
      ~CLock() {}

      void Lock(...) {...}

      void Unlock(...) {...}
  };

  std::vector<CLock> myLockVec;

Как бы ваш вектор CLock знает, как разблокировать все, когда это будет сделано? Векторы не созданы, чтобы знать о блокировках.

По сути, это та же ситуация, что и с вектором указателей:

 std::vector<int*> myIntVec;

Как вектор узнает, какие указатели здесь были удалены и имеют NULL, а какие на самом деле есть? Возможно, некоторые из них были удалены и установлены на ваше специальное значение 0xdeadbeef, то есть удалено.

Дело в том, что вектор не имеет возможности знать это или знать, что его элементы являются указателями, блокировками или чем-то еще. Они просто должны быть объектами, у которых есть конструкторы по умолчанию и которые можно копировать, а также соответствовать другим требованиям, предъявляемым вектором к своим элементам.

Решение состоит в том, чтобы убедиться, что любой вектор HOLDS должен отвечать за его очистку. Это называется RAII - выделение ресурсов - это инициализация, что более важно в данном случае, уничтожение ресурсов - это освобождение. В нашем примере с CLock, приведенном выше, ответ очевиден, не забудьте разблокировать, когда мы закончим!

 class CLock
 {  
      ...
      ~Clock()
      {
          if (locked)
          {
              Unlock();
          }
      }
 } 

Но с указателями это не так очевидно. Решение - заключить указатель в класс smart_ptr.

5
ответ дан 18 December 2019 в 05:18
поделиться

Я полагаю, что вы говорите о std :: vector, а не о языковых массивах.

  1. Когда программа дает сбой, ОС восстанавливает свою память
  2. std :: vector освобождает память что он выделяет. Если вы сохраняете указатели, они не будут удалены.
  3. Векторы создаются, как и любые другие переменные, они не находятся в куче только потому, что они векторы.
4
ответ дан 18 December 2019 в 05:18
поделиться

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

«Каждый раз, когда я запускаю свою программу, я теряю оперативную память», должно быть, из-за какого-то другого эффекта - как вы это измеряете?

] Относительно того, почему вы использовали "новый" - две причины:

  • Вы хотите контролировать, когда они освобождаются
  • Вы хотите, чтобы они сохранялись после выхода из текущей функции.
3
ответ дан 18 December 2019 в 05:18
поделиться

Один из нас двоих здесь немного запутался.

Если вы используете std :: vector, вам не нужно вручную выделять память для его элементов. Дополнительное пространство будет автоматически выделяться при необходимости, когда вы выполняете push_back (). Если вам по какой-то причине нужно предварительно выделить все пространство, вы можете вызвать функцию reserve (). В любом случае, при уничтожении вектора память автоматически освобождается для вас.

Если вы выполняете new std :: vector, вы получаете указатель на вектор. Это ничем не отличается от вызова new для любого другого класса. Вы создаете указатель на объект этого класса, и он будет уничтожен при вызове delete. Если вам не нравится такое поведение, попробуйте создать свой вектор в стеке.

2
ответ дан 18 December 2019 в 05:18
поделиться

Что касается «потерянной памяти», что говорит @RichieHindie.

По второму вопросу:

могут ли векторы, созданные без ключевого слова NEW, действительно быть оставлены на их усмотрение собственные устройства и доверились разобраться с собой, даже если код прерывается в середине потока

В то время как нормальное завершение программы (включая завершение по исключению) гарантирует выполнение деструкторов (с некоторыми придирками относительно статических данных - теоретически они тоже должны выполняться, на практике вы можете иногда получить проблемы), жесткий сбой процесса не может гарантировать какое-либо поведение - например, kill -9 гарантированно завершит вашу программу как можно скорее, не давая ей возможности выполнить какие-либо деструкторы или что-то еще .

1
ответ дан 18 December 2019 в 05:18
поделиться

Another scenario not mentioned in regards to when you'd want to use "new", is in some cases when a vector is a member variable of a class. The NULL can be used as an additional semaphore, for example during create on demand; also, if the vector usage is sparsely populated on your class, then not even creating one unless it's really needed will save you memory, at the expense of the extra 4 byte penalty on all instances as well as the runtime penalty of the pointer indirection.

1
ответ дан 18 December 2019 в 05:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: