Нужно ли удалять массив, хранящийся как статическую локальную переменную, и как? - PullRequest
1 голос
/ 11 сентября 2010

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

void func() {
    static GLfloat arrs[4] = {1, 1, 1, 1};
    static GLUquadric* quad = gluNewQuadric(); // delete with gluDeleteQuadric(quad)
    //... other codes ... 
}

Однако, если бы я использовал static, у меня были бы проблемы с удалением этих ресурсов, так как я не могу получить доступ к этим переменным извне функции. Я могу сделать эти глобалы, но я хотел бы избежать этого, если это возможно.

Так что вопрос:

  1. Распределяется ли arrs [] в стеке или в куче? И так, мне нужно было бы удалить его?
  2. В случае GLUquadric, очевидно, компилятор не знал бы, как правильно его удалить, поскольку сейчас я использовал класс-оболочку RAII , который прекрасно работал, но я смотрю, есть ли более простой подход.

valgrind жаловался на то, что не выпустил GLUquadric, и я думаю, что я просто очистил бы его, а не заставил valgrind замолчать, даже если программа должна была закончиться в любом случае, когда я их выпущу, и эти ресурсы, вероятно, (?) Будут освобождены, когда программа заканчивается.

Ответы [ 7 ]

2 голосов
/ 11 сентября 2010
  1. Нет необходимости удалять arrs [], он не был выделен в куче.Он также не находится в стеке, он где-то находится в сегменте данных и является частью данных вашей статической программы и исчезнет, ​​когда процесс выполнит.

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

Отредактировано: Я все еще беспокоюсь об этом объекте кучи.особенно если это происходит из какой-то библиотеки;Вы никогда не знаете, что происходит внутри, возможно, он заблокировал некоторые аппаратные ресурсы или что-то подобное.Здесь вы ничего не можете сделать с помощью умных указателей и т. Д., Но если вам действительно нужно, чтобы это было размещено таким образом, возможно, стоит зарегистрировать освобождение с помощью функции atexit () или аналогичной.Или поместите все это в глобальный статический одноэлементный объект с деструктором.Вам не о чем беспокоиться, если вы знаете, что объект содержит только данные, то есть не беспокойтесь о своей куче.

1 голос
/ 11 сентября 2010

Поскольку ваша функция «delete» является простой функцией с одним параметром, вы можете использовать ее непосредственно с TR1 (или бустом) shared_ptr с пользовательским средством удаления.

void func()
{
    static std::tr1::shared_ptr<GLUQuadric> quad(gluNewQuadric(), gluDeleteQuadric);
    // ...
}
1 голос
/ 11 сентября 2010

Использовать автоматический ptr:

int myFunc()
{
    static GLfloat                   arrs[4] = {1, 1, 1, 1};
    static std::auto_ptr<GLUquadric> quad    = gluNewQuadric();

    // Do Stuff
}

Статическая переменная инициализируется при первом использовании.
Затем он уничтожается, когда приложение прекращается. Поскольку это умный указатель, он удалит указатель.

1: Распределение arrs [] в стеке или в куче? И так, мне нужно было бы удалить его?

Ни.
И нет, вам не нужно его удалять.
Он имеет статическую продолжительность хранения, это просто означает, что он будет действовать до тех пор, пока основные выходы не будут уничтожены с другими статическими объектами продолжительности хранения (в обратном порядке создания).

2: В случае GLUquadric, очевидно, компилятор не знал бы, как правильно его удалить, поскольку сейчас я использовал класс-оболочку RAII, который прекрасно работал, но я смотрю, есть ли еще более простой подход.

Нет. Просто используйте стандартный, чтобы сделать его максимально простым.

1 голос
/ 11 сентября 2010

По вашему описанию, я предполагаю, что эти статики объявлены внутри функции, которая их использует.В этом случае вам не нужно удалять их.На самом деле, вы не можете удалить их, если хотите.Поскольку функция не будет работать должным образом, если статические данные не будут доступны, вы не можете удалить их.Они не являются переменными стека, поскольку они переживают время жизни функции.

0 голосов
/ 11 сентября 2010

Q1 и Q2: не делайте этого! .Вы не можете использовать std::auto_ptr<GLUquadricObj>, поскольку это ресурс, который должен быть освобожден специализированным удалителем gluDeleteQuadric.Как правило, в движках, управляемых состоянием, таких как OpenGL и GLU, не используются статики - ну, не используйте их никогда, но в контексте OpenGL это особенно опасно.

Опять же, серьезно:

Q1.не делай этогоНет никакой выгоды в хранении статического 4-элементного массива целых чисел.Определите это локально, где вам это нужно.Мой совет: не используйте массивы в стиле c, вместо этого скажите:

const std::array<int, 4> tArray = {1, 1, 1, 1};

Q2.Рекомендации RAII, приведенные выше, хороши, но вам нужна оболочка RAII, которая поддерживает пользовательские удаления:

std::shared_ptr<GLUquadricObj> 
 tMyQuadric(glCreateQuadric(), glDeleteQuadric);

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

0 голосов
/ 11 сентября 2010

Что касается любопытных и будущих ссылок, это мой шаблон RAII:

template <typename T, T* constructor(), void destructor(T*)>
class Managed {
    private:
        T* value;
    public:
        Managed() {
            value = constructor();
        }
        ~Managed() {
            destructor(value);
        }
        T* operator*() {
            return value;
        }
};

и используется так:

typedef Managed<GLUquadric, gluNewQuadric, gluDeleteQuadric> MGLUquadric;
static MGLUquadric quad = MGLUquadric();
gluSphere(*quad, 3.0f, 20, 20);
0 голосов
/ 11 сентября 2010

Основное правило состоит в том, что мы должны удалять только то, что мы выделили.Если мы выделили new, освободите память с помощью delete.Если мы выделили new[], освободим память с delete[].

Так что для

Q1.Нет, не удаляйте.Мы никогда не обновляли его

Q2.Да, нам нужно удалить, предполагая, что функция распределила его.Однако проблема в том, что, глядя на Quadratic, сложно узнать, является ли возвращенный указатель новым только для одного «Quadtric» или «массива Quadtric», или это просто указатель на некоторую статическую переменную где-то.Поэтому используйте delete или delete[] соответственно, если вы выделяете память динамически.

...