2009-04-09 7 views
8

Ich entwickle auf Windows mit DevStudio, in C/C++ unmanaged.Aufruf an _freea wirklich notwendig?

Ich möchte etwas Speicher auf dem Stapel statt des Heaps zuweisen, weil ich nicht mit der Freigabe dieses Speichers manuell umgehen muss (ich weiß über intelligente Zeiger und all diese Dinge. Ich habe einen sehr speziellen Fall von Speicherzuweisung muss ich mich kümmern), ähnlich der Verwendung von A2W() und W2A() Makros.

_alloca tut das, aber es ist veraltet. Es wird empfohlen, stattdessen malloca zu verwenden. Aber _malloca Dokumentation sagt, dass ein Anruf zu ___freea ist obligatorisch für jeden Anruf zu _malloca. Es vereitelt dann meinen Zweck, _malloca zu verwenden, ich werde stattdessen malloc oder neu verwenden.

Jeder weiß, ob ich es schaffen kann, _freea nicht ohne Leckage anzurufen und was sind die Auswirkungen innerlich?

Andernfalls werde ich am Ende nur veraltete _alloca Funktion verwenden.

Antwort

13

Es ist immer wichtig, _freea nach jedem Aufruf von _malloca aufzurufen.

_malloca ist wie _alloca, fügt jedoch zusätzliche Sicherheitsüberprüfungen und Verbesserungen zu Ihrem Schutz hinzu. Daher ist es möglich, dass _malloca auf dem Heap anstelle des Stacks zugewiesen wird. Wenn dies geschieht und Sie _freea nicht aufrufen, erhalten Sie ein Speicherleck.

Im Debug-Modus reserviert _malloca IMMER auf dem Heap, also sollte auch freigegeben werden.

Suchen Sie nach _ALLOCA_S_THRESHOLD für Details, wie die Schwellenwerte funktionieren und warum _malloca anstelle von _alloca vorhanden ist, und es sollte Sinn ergeben.


Edit:

Es gab Kommentare gewesen was darauf hindeutet, dass die Person auf dem Heap zuweisen gerade und intelligente Zeiger verwenden usw.

Es gibt Vorteile Zuführungen zu stapeln, die _malloca Sie bieten Es gibt also Gründe, dies zu tun. _alloca wird auf die gleiche Weise funktionieren, aber es ist viel wahrscheinlicher, dass es zu einem Stack-Überlauf oder anderen Problemen kommt, und bietet leider keine schönen Ausnahmen, sondern neigt eher dazu, den Prozess einfach abzubrechen. _malloca ist in dieser Hinsicht viel sicherer und schützt Sie, aber die Kosten sind, dass Sie noch Ihren Speicher mit _freea freigeben müssen, da es möglich ist (aber im Freigabemodus unwahrscheinlich), dass _malloca beschließen wird, auf dem Heap anstelle des Stapels zuzuweisen.

Wenn Ihr Ziel nur ist, Speicher zu vermeiden, würde ich empfehlen, einen intelligenten Zeiger zu verwenden, der die Speicherfreigabe für Sie übernimmt, wenn das Element den Gültigkeitsbereich verlässt. Dies würde Speicher auf dem Heap zuweisen, aber sicher sein und verhindern, dass Sie den Speicher freigeben müssen. Dies funktioniert jedoch nur in C++. Wenn Sie nur ein altes C verwenden, wird dieser Ansatz nicht funktionieren.

Wenn Sie versuchen, auf dem Stapel aus anderen Gründen zuzuteilen (normalerweise Leistung, da Stapelzuweisungen sehr, sehr schnell sind), würde ich _malloca empfehlen und mit der Tatsache leben, dass Sie _freea auf Ihrem aufrufen müssen Werte.

+1

Nur neugierig, aber warum die Downvotes auf Mitch und meine Posts? Ich würde gerne wissen, warum jemand mit diesem Kommentar nicht einverstanden ist ... vor allem, wenn ich etwas verpasse. –

1

Um Speicher auf dem Stack zuzuordnen, deklarieren Sie einfach eine Variable des entsprechenden Typs und der entsprechenden Größe.

+0

Warum der Downvote? Das Poster fragte nach dem Stack ... –

+0

Es war nicht mein Downvote, aber ich vermute nur, dass er speziell nach _alloca/_malloca gefragt hat, die sehr unterschiedliche Stacknutzungsmuster als Standard-Variablendeklarationen haben. Persönlich stimme ich Ihnen aber auch zu, denn in den meisten Fällen tue ich das, wenn möglich. –

+0

@Reed Copsey: Danke. –

0

Wenn es Ihr Anliegen ist, den temporären Speicher freizugeben, und Sie alles über Dinge wie Smart-Pointer wissen, warum dann nicht ein ähnliches Muster verwenden, wo Speicher freigegeben wird, wenn es den Rahmen verlässt?

template <class T> 
class TempMem 
{ 
    TempMem(size_t size) 
    { 
    mAddress = new T[size]; 
    } 

    ~TempMem 
    { 
    delete [] mAddress; 
    } 

    T* mAddress; 
} 

void foo(void) 
{ 
    TempMem<int> buffer(1024); 

    // alternatively you could override the T* operator.. 
    some_memory_stuff(buffer.mAddress); 

    // temp-mem auto-freed 
} 
3

Eine andere Sache, eine RAII-Klasse zu prüfen, ist mit der Zuordnung zu verwalten - das ist natürlich nur dann sinnvoll ist, wenn Ihr Makro (oder was auch immer) auf C++ beschränkt werden kann.

Wenn Sie den Heap aus Leistungsgründen vermeiden möchten, sehen Sie sich die Techniken an, die von Matthew Wilson's auto_buffer<> Vorlagenklasse (http://www.stlsoft.org/doc-1.9/classstlsoft_1_1auto__buffer.html) verwendet werden. Dies wird auf dem Stapel zugewiesen, es sei denn, Ihre Anforderung für die Laufzeitgröße überschreitet eine zum Zeitpunkt des Compilers angegebene Größe. So erhalten Sie für die meisten Zuordnungen die Geschwindigkeit ohne Heapzuweisung (wenn Sie die Vorlage richtig dimensionieren) diese Größe.

Da STLSoft eine ganze Menge cruft hat mit der Portabilität Probleme zu behandeln, können Sie in einer einfacheren Version von auto_buffer<> aussehen wollen, die in Wilsons Buch beschrieben wird, "Imperfect C++".

fand ich es ganz praktisch in einem eingebetteten Projekt .

+1

+1 auf den Vorschlag auto_buffer <>. Es macht im Grunde, was _malloca anstelle von _alloca auf Windows macht. Es gibt eine Überprüfung, um sicherzustellen, dass Sie Ihr Stack-Limit nicht überschreiten, und es wird, wenn nötig, statt der Stack-Zuweisung Heap-Allokationen durchführen. Das funktioniert aber auch in C. –

1

Ich habe das vorher beantwortet, aber ich hatte etwas Grundlegendes verpasst, was bedeutete, dass es nur im Debug-Modus funktionierte. Ich habe den Aufruf von _malloca in den Konstruktor einer Klasse verschoben, die sich automatisch befreien würde.

In Debug ist das in Ordnung, wie es immer auf dem Heap reserviert. Bei der Freigabe wird es jedoch auf dem Stapel zugeordnet, und bei der Rückkehr vom Konstruktor wurde der Stapelzeiger zurückgesetzt und der Speicher verloren.

Ich ging zurück und nahm einen anderen Ansatz, was zu einer Kombination aus der Verwendung eines Makros (Eurgh) führt, um den Speicher zuzuweisen und ein Objekt zu instanziieren, das _freea automatisch auf diesem Speicher aufruft. Da es sich um ein Makro handelt, wird es im selben Stapelrahmen zugewiesen und funktioniert daher im Freigabemodus. Es ist genauso praktisch wie meine Klasse, aber etwas weniger gut zu benutzen.

Ich habe die folgenden:

class EXPORT_LIB_CLASS CAutoMallocAFree 
{ 
public: 
    CAutoMallocAFree(void *pMem) : m_pMem(pMem) {} 
    ~CAutoMallocAFree() { _freea(m_pMem); } 

private: 
    void *m_pMem; 

    CAutoMallocAFree(); 
    CAutoMallocAFree(const CAutoMallocAFree &rhs); 
    CAutoMallocAFree &operator=(const CAutoMallocAFree &rhs); 
}; 

#define AUTO_MALLOCA(Var, Type, Length) \ 
    Type* Var = (Type *)(_malloca((Length) * sizeof (Type))); \ 
    CAutoMallocAFree __MALLOCA_##Var((void *) Var); 

So kann ich den folgenden Makro-Aufruf zuordnen kann, und es wird freigegeben, wenn die instanziierten Klasse aus dem Geltungsbereich:

  AUTO_MALLOCA(pBuffer, BYTE, Len); 
      Ar.LoadRaw(pBuffer, Len); 

Ich entschuldige mich für die Buchung etwas, das eindeutig falsch war!

0

Wenn Sie _malloca() verwenden, müssen Sie _freea() aufrufen, um Speicherverlust zu vermeiden, da _malloca() die Zuordnung entweder auf Stapel oder Heap ausführen kann. Wenn der angegebene Wert für overall_ALLOCA_S_THRESHOLD den angegebenen Wert überschreitet, greift er auf den Heap zu. Daher ist es sicherer, _freea() aufzurufen, was nichts tun wird, wenn die Zuordnung auf dem Stack erfolgt.

Wenn Sie _alloca() verwenden, scheint dies ab heute veraltet zu sein; Es ist nicht erforderlich, _freea() aufzurufen, da die Zuweisung auf dem Stack erfolgt.