Pérdida de memoria durante un_orped_map :: inserte la excepción KeyEqual con GCC - ¿rompiendo la fuerte garantía de seguridad de excepción?

10

Estoy usando GCC 7.3.1, pero también probé en coliru, que creo que es la versión 9.2.0. Construir con lo siguiente:

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

Aquí está 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";
    }
}

Ejecutarlo da como resultado:

> ./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).

No veo ninguna pérdida de memoria con Visual C ++ ( Microsoft (R) C/C++ Optimizing Compiler Version 19.24.28314 for x64).

¿Esto rompe la fuerte garantía de seguridad de excepción de unordered_map::insert( https://stackoverflow.com/a/11699271/1958315 )? ¿Es esto un error en el GCC STL?

Rai
fuente
El STL solo detectará las excepciones que genera (si puede). No va a proteger contra que rompas, es invariante. Buen CPPCON habla sobre esto: youtube.com/…
NathanOliver
1
@ NathanOliver-ReinstateMonica probablemente la documentación necesita ser actualizada entonces, como std::unordered_map::insertdice claramente "1-4) Si alguna operación arroja una excepción , la inserción no tiene efecto". (el énfasis es mío) desde aquí en.cppreference.com/w/cpp/container/unordered_map/insert
Slava
libc ++ no pierde ninguna memoria al ejecutar este programa.
Marshall Clow
@ NathanOliver-ReinstateMonica no tiene sentido. La biblioteca estándar tiene que manejar excepciones de los tipos que el usuario define. No hay invariantes rotos aquí.
Jonathan Wakely
@Rai esto es un error, por favor repórtelo gcc.gnu.org/bugs
Jonathan Wakely

Respuestas:

2

La garantía exigida por la norma (citas del último borrador):

[contenedor.requirements.general]

A menos que se especifique lo contrario (consulte [associative.reqmts.except], [unord.req.except], [deque.modifiers] y [vector.modifiers]) todos los tipos de contenedor definidos en esta Cláusula cumplen los siguientes requisitos adicionales:

  • Si una función insert () o emplace () genera una excepción al insertar un solo elemento, esa función no tiene efectos.

[associative.reqmts.except]

Para contenedores asociativos, si una operación es lanzada por una operación desde una función de inserción o inserción que inserta un solo elemento, la inserción no tiene efecto.

[unord.req.except]

Para contenedores asociativos desordenados, si una operación es lanzada por una operación que no sea la función hash del contenedor desde una inserción o función de inserción que inserta un solo elemento, la inserción no tiene efecto.

Según tengo entendido, "no tiene efecto" implica "sin pérdida de memoria". Bajo tal interpretación, consideraría que una fuga es un error.

eerorika
fuente