Как избежать динамического выделения памяти C ++

0

[edit] Вне этого метода get (см. ниже), я хотел бы получить double * result; указатель double * result; а затем вызовите метод get, т.е.

    // Pull results out
    int story = 3;
double * data;
int len;
m_Scene->GetSectionStoryGrid_m(story, data, len);

с этим сказал, я хочу метод get, который просто устанавливает результат (* & data) по ссылке и не динамически выделяет память.

Результаты, которые я ищу, уже существуют в памяти, но они находятся внутри C-структур и не находятся в одном непрерывном блоке памяти. Fyi, & len - это просто длина массива. Я хочу один большой массив, который содержит все результаты.

Поскольку фактические результаты, которые я ищу, хранятся внутри собственного указателя C-struct story_ptr->int_hv[i].ab.center.x; , Как мне избежать динамического выделения памяти, как я делаю выше? Id хотел бы указать данные * на результаты, но я просто не знаю, как это сделать. Вероятно, это что-то простое, я пропускаю... Код ниже.

Возможно ли это? Из того, что я читал, это не так, но, как следует из моего имени пользователя, я не разработчик программного обеспечения. Спасибо всем, кто ответил до сих пор, кстати!

Вот фрагмент кода:

void GetSectionStoryGrid_m( int story_number, double *&data, int &len )
{

    std::stringstream LogMessage;

    if (!ValidateStoryNumber(story_number))
    { 
            data = NULL;
            len = -1;
    }
    else
    {
            // Check to see if we already retrieved this result
            if ( m_dStoryNum_To_GridMap_m.find(story_number) == m_dStoryNum_To_GridMap_m.end() )
            {
                    data   = new double[GetSectionNumInternalHazardVolumes()*3];
                    len = GetSectionNumInternalHazardVolumes()*3;

                    Story * story_ptr = m_StoriesInSection.at(story_number-1);
                    int counter = 0;  // counts the current int hv number we are on

                    for ( int i = 0; i < GetSectionNumInternalHazardVolumes() && story_ptr->int_hv != NULL; i++ )  
                    {  
                            data[0 + counter] = story_ptr->int_hv[i].ab.center.x;
                            data[1 + counter] = story_ptr->int_hv[i].ab.center.y;
                            data[2 + counter] = story_ptr->int_hv[i].ab.center.z;

                            m_dStoryNum_To_GridMap_m.insert( std::pair<int, double*>(story_number,data));

                            counter += 3;
                    }
            }
            else
            {
                    data = m_dStoryNum_To_GridMap_m.find(story_number)->second;
                    len = GetSectionNumInternalHazardVolumes()*3;
            }
    }
}
  • 1
    Вы хотите избежать динамического распределения (т.е. данных переменного размера, возможно, хранящихся в куче) ? Или вы пытаетесь избежать ручного управления памятью (т. Е. Использования new / delete и высокого риска утечек памяти и висячих указателей) ? Первое не обязательно должно сопровождаться вторым.
  • 0
    Привет, Бенджамин, я стараюсь избегать того и другого. Я знаю, что данные, которые мне нужны, находятся где-то в памяти (внутри C-структур), поэтому в идеале я хотел бы, чтобы указатель указывал на эти данные и просто использовал их. Я предполагаю, что моей главной проблемой является нехватка памяти (этот проект довольно большой), поэтому я хотел бы избежать создания копии того, что уже находится в памяти (избегайте new / delete).
Показать ещё 4 комментария
Теги:
memory
memory-management

3 ответа

4
Лучший ответ

Подумайте о возврате пользовательского класса accessor вместо "double * & data". В зависимости от ваших потребностей класс будет выглядеть примерно так:

class StoryGrid {
    public:
        StoryGrid(int story_index):m_storyIndex(story_index) {
            m_storyPtr =  m_StoriesInSection.at(story_index-1);
        }
        inline int length() { return GetSectionNumInternalHazardVolumes()*3; }

        double &operator[](int index) {
            int i = index / 3;
            int axis = index % 3;
            switch(axis){
                case 0: return m_storyPtr->int_hv[i].ab.center.x;
                case 1: return m_storyPtr->int_hv[i].ab.center.y;
                case 2: return m_storyPtr->int_hv[i].ab.center.z;
            }
        } 
};

Извините за любые проблемы с синтаксисом, но вы получите эту идею. Верните ссылку на это и запишите это на своей карте. Если все сделано правильно, карта с последующим управлением всем необходимым динамическим распределением.

  • 0
    Чувак, это сладкое решение, но единственный недостаток в том, что я обязан вернуть двойной * &. Я определенно собираюсь помнить этот трюк в будущем. Спасибо!
2

Таким образом, вы хотите, чтобы выделенный массив переместился "вниз" в стек вызовов. Вы можете достичь этого, выделив его в кучу, используя динамическое распределение. Или создание static переменной, поскольку жизненный цикл static переменных не контролируется стеком вызовов.

void GetSectionStoryGrid_m( int story_number, double *&data, int &len )
{
    static g_data[DATA_SIZE];
    data = g_data;
    // continues ...

Если вы хотите "избежать любого выделения", решение от @Speed8ump - ваш первый выбор! Но тогда у вас не будет вашего double * result; больше. Вы будете превращать свое "автономное" решение (сначала вычисляет весь массив, а затем использовать массив в другом месте) в "онлайн-решение" (вычисляет значения по мере необходимости). Это хороший рефакторинг, чтобы избежать выделения памяти.

  • 0
    Спасибо за ответ! В идеале я бы хотел избежать какого-либо выделения, поскольку это уже было сделано на стороне C в их структурах. Но я не уверен, что то, что я хочу, даже возможно (см. Отредактированный пост). Еще раз спасибо :)
0

Этот ответ на этот вопрос зависит от времени жизни double к double вы хотите указать указатели. Рассматривать:

// "pointless" because it takes no input and throws away all its work
void pointless_function()
{
    double foo = 3.14159;
    int j = 0;
    for (int i = 0; i < 10; ++i) {
        j += i;
    }
}

foo существует и имеет значение внутри pointless_function, но перестает существовать, как только функция завершается. Даже если вы могли бы получить указатель на него, этот указатель был бы бесполезен за пределами pointless_function. Это был бы висячий указатель, и разыменование его вызывало бы неопределенное поведение.

С другой стороны, вы правы, что если у вас есть данные в памяти (и вы можете гарантировать, что он будет жить достаточно долго для того, что вы хотите с ним делать), может быть хорошей идеей получить указатели на эти данные, а не платить стоимость его копирования. Однако основной способ передачи данных для функции, создающей ее, - это вызов new, new[] или malloc. Вы действительно не можете уйти от этого.

Глядя на код, который вы опубликовали, я не вижу, как вы можете избежать new[] -ing удвоений при создании story. Но затем вы можете получить указатели на эти двойники позже, не требуя повторного вызова new или new[].


Следует отметить, что указатели на данные могут использоваться для изменения исходных данных. Часто это может привести к ошибкам, затрудняющим отслеживание. Таким образом, есть время, когда лучше заплатить цену за копирование данных (которые вы тогда можете гасить, как хотите), или получить указатель на константу (в данном случае const double* или double const*, они эквивалентны: указатель-на-const даст вам ошибку компилятора, если вы попытаетесь изменить отображаемые данные). Фактически, так часто бывает, что совет должен быть инвертирован: "Есть несколько раз, когда вы не хотите копировать или получать указатель на константу, в этих случаях вы должны быть очень осторожны".

  • 2
    Данные также могут пережить функцию, если переменные объявлены как static в области действия функции.
  • 0
    const double* и double const* не эквивалентны!
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню