【问题标题】:How to avoid dynamic allocation of memory C++如何避免动态分配内存 C++
【发布时间】:2023-04-10 16:10:01
【问题描述】:

[编辑] 在这个 get 方法之外(见下文),我想要一个指针 double * result; 然后调用 get 方法,即

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

话虽如此,我想要一个 get 方法,它通过引用简单地设置结果 (*&data),而不是动态分配内存。

我正在寻找的结果已经存在于内存中,但它们在 C 结构中并且不在一个连续的内存块中。仅供参考,&len 只是数组的长度。我想要一个包含所有结果的大数组。

由于我要查找的实际结果存储在本机 C 结构指针 story_ptr->int_hv[i].ab.center.x; 中。我将如何避免像上面那样动态分配内存?我想将数据*指向结果,但我只是不知道该怎么做。可能是我忽略了一些简单的东西……代码如下。

这甚至可能吗?根据我的阅读,它不是,但正如我的用户名所暗示的那样,我不是软件开发人员。感谢所有到目前为止回复的人!

这是一段sn-p代码:

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;
            }
    }
}

【问题讨论】:

  • 它实际上是动态分配(即可变大小的数据,可能存储在堆上)你想避免吗?还是您要避免的手动内存管理(即使用new/delete,以及内存泄漏和悬空指针的高风险)?第一个不一定要伴随第二个。
  • 嗨,本杰明,我正试图避免这两种情况。我知道我想要的数据在内存中的某个地方(在 C 结构中),所以理想情况下,我想要一个指向该数据的指针并使用它。我想我主要担心内存不足(这个项目非常大),所以我想避免创建内存中已有内容的副本(避免新建/删除)。
  • 我不太确定我得到了你想要的,但听起来你需要一个迭代器类。您可以返回的东西,客户端可以将其视为指针,但在迭代器中,它包含用于查找和返回值的数据和代码。
  • 我试图通过编辑上面的帖子来澄清我的问题。我不确定我想要什么是可能的。看起来我必须分配内存,因为我绝对需要返回一个双精度数组。
  • 如果您无法更改要返回的类型,我怀疑是否有任何方法可以避免将存储的值重新组织到另一个数组中。

标签: c++ c memory memory-management


【解决方案1】:

考虑返回一个自定义访问器类而不是“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;
            }
        } 
};

抱歉有任何语法问题,但你明白了。返回对此的引用并将其记录在您的地图中。如果正确完成映射,则管理所需的所有动态分配。

【讨论】:

  • 伙计,这是一个很好的解决方案,但唯一的缺点是我需要返回一个双 *&。我将来肯定会记住这个技巧。谢谢!
【解决方案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;。您将把“离线”解决方案(首先计算整个数组,然后在其他地方使用数组)转换为“在线”解决方案(根据需要计算值)。这是避免内存分配的良好重构。

【讨论】:

  • 感谢您的回复!理想情况下,我想避免任何分配,因为它已经在其结构中的 C 端完成。但是,我不确定我想要的是否可能(见编辑后的帖子)。再次感谢:)
【解决方案3】:

此问题的答案取决于您想要指向的 doubles 的生命周期。考虑:

// "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 之外也是无用的。这将是一个悬空指针,取消引用会触发undefined behavior

另一方面,您是正确的,如果您在内存中有数据(并且您可以保证它的寿命足够长,可以用于您想用它做的任何事情),它可能会很棒想法获取指向该数据的指针,而不是支付复制它的成本。但是,数据比创建它的函数更有效的主要方法是调用newnew[]malloc。你真的无法摆脱它。

查看您发布的代码,我不明白您如何避免 new[]-在创建 story 时添加双打。但是您可以稍后获得指向这些双精度的指针,而无需再次调用 newnew[]


我应该提到,指向数据的指针可以用来修改原始数据。这通常会导致难以追踪的错误。因此,有时最好支付复制数据的代价(然后您可以随意使用这些数据),或者获取指向 const 的指针(在这种情况下为 const double*double const* ,它们是等价的;如果您尝试更改指向的数据,指向 const 的指针会给您一个编译器错误)。事实上,这种情况经常发生,建议应该颠倒过来:“有几次你不想想要复制或获取指向 const 的指针;在这些情况下,你必须小心点。”

【讨论】:

  • 如果变量在函数范围内声明为static,数据也可以比函数寿命更长。
  • const double*double const* 不等价!
  • @ericbn:有些事情我总是出错,所以在发布之前我必须仔细检查 const 语法。 const double* 和 double const* 都是指向 const 的指针。 double* const 是一个指向可变数据的 const 指针(stroustrup.com/bs_faq2.html#constplacement,尤其是最后三行)。
猜你喜欢
  • 2021-04-24
  • 1970-01-01
  • 2012-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-07
  • 2015-06-27
  • 2021-02-28
相关资源
最近更新 更多