Избегать new () при инициализации статических членов? - PullRequest
0 голосов
/ 08 июля 2011

Код, о котором идет речь, выглядит следующим образом:

заголовок:


  class Vec3d : public Object {
    public:
      static linearalgebra::Vec3d* X_AXIS;
      static linearalgebra::Vec3d* Y_AXIS;
      static linearalgebra::Vec3d* Z_AXIS;
      static linearalgebra::Vec3d* AXES[3];

      static int f();
  };

реализация: <pre> Vec3d* Vec3d::X_AXIS = new Vec3d(); Vec3d* Vec3d::Y_AXIS = new Vec3d(); Vec3d* Vec3d::Z_AXIS = new Vec3d(); Vec3d* Vec3d::AXES[3] = {Vec3d::X_AXIS, new Vec3d(),Vec3d::Z_AXIS};</p> <p>int Vec3d::f() { X_AXIS = AXES[2]; }

Есть ли способ не использовать этиоператоры new (), но без добавления каких-либо новых вспомогательных переменных?

Типы должны быть в точности такими, какие они есть, чтобы быть совместимыми с остальной частью программы.

РЕДАКТИРОВАТЬ : угадывая из ответов, необходимо использовать new ()если вспомогательные переменные не используются.Это правда?Таким образом, я мог бы добавить вспомогательные переменные.В любом случае, это код, сгенерированный компилятором, так что нет проблем, если заголовки доступны для чтения.

Будет ли хорошо следующее?Теперь Вальгринд говорит, что утечек нет.


  static Vec3d INIT_X_AXIS;
  static Vec3d INIT_Y_AXIS;
  static Vec3d INIT_Z_AXIS;
  static Vec3d INIT_AXES_1;

  Vec3d* Vec3d::X_AXIS = &INIT_X_AXIS;
  Vec3d* Vec3d::Y_AXIS = &INIT_Y_AXIS;
  Vec3d* Vec3d::Z_AXIS = &INIT_Z_AXIS;
  Vec3d* Vec3d::AXES[3] = {Vec3d::X_AXIS, &INIT_AXES_1, Vec3d::Z_AXIS};

Ответы [ 7 ]

1 голос
/ 08 июля 2011

Это нормально в C ++, если эти указатели никогда не освобождаются?

Определить "ОК".Будет ли ваша программа работать?Да.Это хорошая идея? Нет!

Мне кажется, вам было бы лучше с этим:

class Vec3d : public Object {
public:
    static linearalgebra::Vec3d xAxisMemory;
    static linearalgebra::Vec3d yAxisMemory;
    static linearalgebra::Vec3d zAxisMemory;
    static linearalgebra::Vec3d axesMemory[3];

    static linearalgebra::Vec3d* X_AXIS;
    static linearalgebra::Vec3d* Y_AXIS;
    static linearalgebra::Vec3d* Z_AXIS;
    static linearalgebra::Vec3d* AXES[3];

    static int f();
};


Vec3d Vec3d::xAxisMemory;
Vec3d Vec3d::xAxisMemory;
Vec3d Vec3d::xAxisMemory;
Vec3d Vec3d::axesMemory[3];

Vec3d* Vec3d::X_AXIS = &xAxisMemory;
Vec3d* Vec3d::Y_AXIS = &yAxisMemory;
Vec3d* Vec3d::Z_AXIS = &zAxisMemory;
Vec3d* Vec3d::AXES[3] = {&axesMemory[0], &axesMemory[1], &axesMemory[2]};
1 голос
/ 08 июля 2011

Если вы хотите оставить все как есть, вы можете это сделать (что не очень хороший дизайн, но должен работать).Я не пытался строить, но все должно быть в порядке.

Vec3d* Vec3d::X_AXIS = NULL;
Vec3d* Vec3d::Y_AXIS = NULL;
Vec3d* Vec3d::Z_AXIS = NULL;
Vec3d* Vec3d::AXES[3] = { 0 };

namespace {
    const struct Initializer {
        Initializer() {
            static Vec3d x, y, z;
            AXES[0] = X_AXIS = &x;
            AXES[1] = Y_AXIS = &y;
            AXES[2] = Z_AXIS = &z;
        }
    } Init;
}
1 голос
/ 08 июля 2011

Любой ресурс памяти, который получен, но не возвращен, считается утечкой памяти. Таким образом, если вы получили динамическую память, используя new(), если вы не освободили выделенную память с помощью callnig delete(), вы вызываете утечку памяти.

Какие у вас есть варианты?

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

Лучшая альтернатива:
Вам следует рассмотреть возможность использования Smart Pointers вместо необработанных указателей.
С умными указателями Вам не нужно беспокоиться о явном вызове delete, если вы используете умные указатели. Как только не останется ссылок на эти статические типы, они будут удалены неявно . Таким образом, каждый ресурс сам заботится о своем освобождении.

1 голос
/ 08 июля 2011

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

0 голосов
/ 08 июля 2011

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

Вы можете попытаться создать другую статическую переменную, которая будет действовать как счетчик ссылок. В конструкторе вы добавляете +1 к нему, а в деструкторе вы делаете -1 на нем. В деструкторе после выполнения минус 1 вы проверяете, равна ли переменная 0, и если да, вы вызываете delete для статических членов.

Заголовок:

static int  _refCount;

Реализация:

int Vec3d::_refCount = 0;

Vec3d::Vec3d()
{
    _refCount += 1;
}

virtual Vec3d::~Vec3d()
{
    _refCount -= 1;
    if (_refCount == 0)
    {
        //delete all allocated memory in static variables
    }
}

.. или вы можете просто использовать Smart Pointer реализацию.

0 голосов
/ 08 июля 2011

1) использовать умные указатели для автоматического освобождения памяти

2) добавить статическую функцию для освобождения памяти и зарегистрировать ее в «atexit»

0 голосов
/ 08 июля 2011

Если вы не освобождаете память после new, то это утечка памяти.Вы должны delete/delete[].

Если вы хотите запретить использование new для Vec3d, сделайте их private и не реализованными:

class Vec3d {
private:
  void* operator new (std::size_t); // don't implement it
public:
//...
};

Таким образом компилятор не позволитиспользовать new() на Vec3d.Также вы можете подумать о создании этой переменной в автоматическом хранилище.Просто не объявляйте их как указатели, а как объекты.

static linearalgebra::Vec3d X_AXIS;
...