簡體   English   中英

C ++內存管理:從函數中的向量創建新數組

[英]C++ memory management: creating a new array from vectors in a function

假設我有一個未分配的浮點數數組

float *a;

然后,我使用函數g,在該函數中我希望對函數范圍之外的數組進行重新分配(因此,我將調用g(&a))。

void g(float** f)
{
  std::vector<float> *v = new std::vector<float>(10);
  *f = &v[0]
}

這會是一個問題嗎? 我確實覺得v的分配比簡單的float數組占用更多的空間。 因此,如果我確實刪除了* f超出了此函數的范圍,則向量v的內存中仍可能殘留一些東西。如果是的話,如何安全地這樣做呢? 重要的是(在我的實際函數中)我確實需要在g內使用一個向量,並且確實需要在g內分配* f,以便* f具有v的內容並且不會在g的范圍之外消失。

我們可以設想這是什么...

std::vector<float> *v = new std::vector<float>(10);

...做這樣的事情:

1) At memory address &v std::vector<float>* v
                      |
                      v
2) At memory address v  std::vector<float>
                      |
                      v
3) At memory address v.data() aka &v[0]  floats[capacity]

在這三個內存位置中:

1)go在堆棧上,並且在g()退出時超出范圍

2)坐在那里直到delete v完成,這在您建議的代碼中永遠不會發生

3)可能已經由向量分配了,但是向量也可以自由分配內存,然后開始將float數據以一定的偏移量放入其中,因此,使用數據地址進行的任何重新分配嘗試都可能導致使用地址為' t由new返回-這是不確定的行為。 這比聽起來的可能性更大,因為必須使用new[]分配的一些內存來存儲元素的數量,以便delete[]可以正確次數調用它們的析構函數-可能在數據之前或之后。 當然,實現還可以將其他內容放入動態分配的內存中:例如,與在有效索引之前或之后立即檢測意外內存訪問相關的值。

我不建議這樣做,但要承認您可能會查看vector實現並刪除3),但是它不可移植,並且可能會因優化級別和其他編譯器選項而中斷。

您沒有機會刪除2)您建議的代碼-根據您的應用程序,可能是可接受的泄漏。

總的來說,我的建議從好到壞:

1)我知道你說不能,但我必須說:盡可能地通過引用或值重寫代碼以使用/傳遞std::vector<float> ,完全避免任何顯式的newdelete

2)如果不是很慢就將數據從vector復制到普通浮點數組

3)您說您需要在g()內添加一個std::vector ,也許您可​​以探索使用備用分配器實例化是否可以通過“取消鏈接”已分配的內存為您提供定義良好的行為,或者(更糟糕的是,它意味着破壞動態調整大小對於push_back等),向向量指定要使用的new[] -ed緩沖區(但在銷毀時不是delete[] )...我還沒有深入研究分配器,以了解這是多么可行。

4)您可能可以編寫具有所需行為的類向量類,最好是一個最小接口,僅支持絕對必要的行為,但是如果您需要大量的向量行為,則最好是硬着頭皮復制和修改標准vector實現

是的,這將是一個問題:如果您為std::vector<float>分配了new ,則需要delete std::vector<float>並且無法從元素地址獲取容器。 如果我真的必須分配一些東西,我可能會這樣做

template <typename Range>
std::unique_ptr<typename Range::value_type[]> copy(Range const& r) {
    using value_type = typename Range::value_type;
    std::unique_ptr<value_type[]> rc(new value_type[r.size()]);
    std::copy(r.begin(), r.end(), rc.get());
    return rc;
}

在做類似的事情之前,我會盡力重新設計正在做的事情。

這里有幾個問題。

void g(float** f);  // will allocate a new array of floats.

// usage:
float* foo;
g(&foo);  // now foo is allocated.

// reclaim the memory:
delete [] foo;   // is this right?
free foo;        // is this right?

任何時候只要有一個函數返回動態分配的內存,就需要知道如何分配內存(new,new [],malloc),以便可以正確地釋放它(delete,delete [],free)。 如果您越過溪流,就會發生壞事。

現在,為您的代碼的特定部分:

void g(float** f)
{
  //  This allocates a new vector.  Key words:  'new' 'vector'
  std::vector<float> *v = new std::vector<float>(10);
  *f = &v[0];  // Now you're returning a pointer to the internals of this new vector.
  // but then the vector [v] is forgotten, so how can you ever clean it up properly?
}

清理v的唯一正確方法是調用delete v; delete因為它是用new分配的)。 但是,在此函數之外,沒有向量的知識(使用此向量的任何人都會認為它只是new[]ed數組)。 所以這行不通。

相反,您可以只使用向量作為實數:

void g(vector<float>* f);
// Usage:
//   vector<float> foo;
//   g(&foo);

沒有動態分配,沒有new ,沒有原始指針,更干凈。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM