es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Constructor predeterminado no inicializado en c++: munmap_chunk(): puntero inválido.

Teniendo este código:

#include <iostream>
#include <iterator>
#include <initializer_list>
#include <algorithm>

class Foo {
public:
Foo() = default;
explicit Foo(size_t size) :size(size){
ar = new double[size];
}
Foo(std::initializer_list<double> initList): Foo(initList.size()){
std::copy(initList.begin(), initList.end(), ar);
}
Foo(double values, size_t size):size(size), ar(values){}
Foo(const Foo &rhs): Foo(rhs.size){
std::copy(rhs.ar, rhs.ar+size, ar);
}
~Foo(){delete[] ar;}
Foo &operator=(Foo rhs){
swap(
this, rhs);
return *this;
}

void print(){
    std::copy(ar, ar+size, std::ostream_iterator&lt;double&gt;(std::cout, &quot; &quot;));
    std::cout &lt;&lt; std::endl;
}

private:
size_t size;
double *ar;

static void swap(Foo &amp;f, Foo &amp;s){
    std::swap(f.size, s.size);
    std::swap(f.ar, s.ar);
}

};

int main() {
using namespace std;

size_t size = 100;
auto *values = new double[size];
for(int i = 0; i&lt;100; i++){
    double fraction = ((10+i) % 10) / 10.0;
    values[i] = i + fraction;
}

Foo f(values, size);
// Foo g; //IF THIS IS NOT BRACED-INITIALIZED, I GOT munmap_chunk(): invalid pointer
Foo g{};
g = f;
g.print();

}

La única diferencia entre el programa que se ejecuta y el que da error es si inicializo la clase Foo g con llaves o no. ¿Por qué es importante? Sé que las llaves van a valor-inicializar la clase, lo que significa que el int *ar sería nullptr. Si no se inicializa con llaves, entonces el int *ar es indeterminado. ¿Pero qué significa eso? ¿Cómo puede ser un puntero indeterminado? ¿Es lo mismo que nullptr? ¿Y por qué falla el programa cuando el puntero es indeterminado?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Cuando Foo g no está inicializado con llaves, el puntero int *ar no se inicializa, lo que significa que contiene valores basura de la memoria. Este estado del puntero se llama indeterminado, lo que significa que puede contener cualquier valor, no necesariamente nullptr.

    En este caso, cuando Foo g no está inicializado, la variable miembro size del objeto g se inicializa a algún valor basura y se llama al constructor Foo(const Foo &rhs), que copia los valores basura de rhs a g. Cuando g se destruye al final de main(), el destructor intenta eliminar el valor del puntero basura en su variable miembro ar, lo que causa un comportamiento indefinido y probablemente hace que el programa falle.

    Por otro lado, cuando se inicializa con llaves Foo g{} obtiene una inicialización de valor, lo que significa que su variable miembro int *ar se inicializa a nullptr. Esto evita valores de puntero basura y asegura que el destructor no intentará eliminar un puntero inválido, evitando que el programa falle.

    En C++, las variables no inicializadas pueden causar comportamiento indefinido, por lo que siempre es importante inicializar las variables en un estado conocido.

Comments are closed.