Perdita di memoria durante unordered_map :: insert Eccezione KeyEqual con GCC - rompendo la forte garanzia di sicurezza delle eccezioni?


10

Sto usando GCC 7.3.1, ma anche testato su coliru, che credo sia la versione 9.2.0. Costruire con il seguente:

g++ -fsanitize=address -fno-omit-frame-pointer rai.cpp

Ecco rai.cpp:

#include <iostream>
#include <unordered_map>

int main()
{
    try
    {
        struct MyComp {
            bool operator()(const std::string&, const std::string&) const {
                throw std::runtime_error("Nonono");
            }
        };

        std::unordered_map<std::string, std::string, std::hash<std::string>, MyComp> mymap;
        mymap.insert(std::make_pair("Hello", "There"));
        mymap.insert(std::make_pair("Hello", "There")); // Hash match forces compare
    } catch (const std::exception& e) {
        std::cerr << "Caught exception: " << e.what() << "\n";
    }
}

L'esecuzione si traduce in:

> ./a.out
Caught exception: Nonono

=================================================================
==72432==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 32 byte(s) in 1 object(s) allocated from:
...

Direct leak of 4 byte(s) in 1 object(s) allocated from:
...

Indirect leak of 60 byte(s) in 2 object(s) allocated from:
...

SUMMARY: AddressSanitizer: 96 byte(s) leaked in 4 allocation(s).

Non vedo perdite di memoria con Visual C ++ ( Microsoft (R) C/C++ Optimizing Compiler Version 19.24.28314 for x64).

Ciò rompe la forte garanzia di sicurezza delle eccezioni di unordered_map::insert( https://stackoverflow.com/a/11699271/1958315 )? È un bug nel GCC STL?


L'STL rileverà solo le eccezioni che genera (se possibile). Non ti proteggerà dalla rottura, è invariante. Bene CPPCON ne parliamo: youtube.com/…
NathanOliver

1
@ NathanOliver-ReinstateMonica probabilmente la documentazione deve essere aggiornata, come std::unordered_map::insertdice chiaramente "1-4) Se un'eccezione viene generata da qualsiasi operazione , l'inserimento non ha alcun effetto." (l'enfasi è mia) da qui en.cppreference.com/w/cpp/container/unordered_map/insert
Slava

libc ++ non perde memoria durante l'esecuzione di questo programma.
Marshall Clow,

@ NathanOliver-ReinstateMonica è una sciocchezza. La libreria standard deve gestire le eccezioni dai tipi definiti dall'utente. Non c'è invariante rotto qui.
Jonathan Wakely,

@Rai questo è un bug, per favore segnalalo gcc.gnu.org/bugs
Jonathan Wakely

Risposte:


2

La garanzia richiesta dalla norma (citazioni dell'ultima bozza):

[Container.requirements.general]

Se non diversamente specificato (vedere [associative.reqmts.except], [unord.req.except], [deque.modifiers] e [vector.modifiers]) tutti i tipi di contenitori definiti in questa clausola soddisfano i seguenti requisiti aggiuntivi:

  • se un'eccezione viene generata da una funzione insert () o emplace () durante l'inserimento di un singolo elemento, tale funzione non ha effetti.

[Associative.reqmts.except]

Per i contenitori associativi, se un'eccezione viene generata da qualsiasi operazione all'interno di una funzione insert o emplace che inserisce un singolo elemento, l'inserimento non ha alcun effetto.

[Unord.req.except]

Per i contenitori associativi non ordinati, se un'eccezione viene generata da qualsiasi operazione diversa dalla funzione hash del contenitore dall'interno di una funzione insert o emplace che inserisce un singolo elemento, l'inserimento non ha alcun effetto.

Per quanto ho capito, "non ha alcun effetto" implica "nessuna perdita di memoria". Sotto tale interpretazione, considererei una perdita un errore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.