Pregunta

Tengo una aplicación automática del puntero:

template <typename T, bool Arr = false>
class GAutoPtr
{
    T *Ptr;

public:
    typedef GAutoPtr<T, Arr> &AutoPtrRef;

    GAutoPtr(T *ptr = 0)
    {
        Ptr = ptr;
    }

    GAutoPtr(AutoPtrRef p)
    {
        Ptr = p.Release();
    }

    ~GAutoPtr() { Empty(); }
    operator T*() { return Ptr; }
    T *Get() { return Ptr; }
    T *operator->() const { LgiAssert(Ptr); return Ptr; }

    inline void Empty()
    {
        if (Arr)
            delete [] Ptr;
        else
            delete Ptr;
        Ptr = 0;
    }

    AutoPtrRef operator =(GAutoPtr<T> p)
    {
        Empty();
        Ptr = p.Ptr;
        p.Ptr = 0;
        return *this;
    }

    void Reset(T *p)
    {
        if (p != Ptr)
        {
            Empty();
            Ptr = p;
        }
    }

    T *Release()
    {
        T *p = Ptr;
        Ptr = 0;
        return p;
    }
};

typedef GAutoPtr<char, true> GAutoString;
typedef GAutoPtr<char16, true> GAutoWString;

Y que funciona bien en Visual C ++ 6. Sin embargo, en Visual C ++ 2005 o 2008 no puedo devolver un puntero automático de una función sin cosas van muy mal.

por ejemplo.

GAutoString Func()
{
    char *s = new char[4];
    strcpy(s, "asd");
    return s;
}

int main()
{
    GAutoString a = Func();
    /// a.Ptr is now garbage
}

Lo que sucede es que el compilador crea un GAutoString temporal para mantener el valor de retorno de la función, y después de pasada que a la variable 'a' en la pila Calles del operador T * () de la variable temporal, y luego la GAutoPtr (T * ptr = 0) constructor, en lugar de usar el constructor de copia: GAutoPtr (AutoPtrRef p)

Esto se traduce en el PTR auto temp borrar la memoria y 'a' la celebración de un puntero a la memoria liberada.

Sin embargo, en VC6 sí pide el constructor derecha. Ahora en decir todo esto también lo uso gcc en Linux y Mac, por lo que cualquier código que escribo tiene que trabajar allí también. VC2008 le impide utilizar un no constante por la variable valor en el constructor de copia. También no quiero "const" de todos modos, porque el constructor de copia toma posesión del bloque de memoria que elimina la propiedad del objeto que está siendo copiado ... modificando así la misma.

¿Cómo puedo hacer que esto funcione en VC 2005/2008?

¿Fue útil?

Solución

Esto es propio de compilación bajo un reciente g ++? Lo he probado en mi MacBook Pro y:

xxx.cpp: In function ‘AutoString func()’:
xxx.cpp:52: error: no matching function for call to ‘AutoPtr<char, true>::AutoPtr(AutoString)’
xxx.cpp:12: note: candidates are: AutoPtr<T, isArray>::AutoPtr(AutoPtr<T, isArray>&) [with T = char, bool isArray = true]
xxx.cpp:9: note:                 AutoPtr<T, isArray>::AutoPtr(T*) [with T = char, bool isArray = true]
xxx.cpp:52: error:   initializing temporary from result of ‘AutoPtr<T, isArray>::AutoPtr(T*) [with T = char, bool isArray = true]’

La única manera que puedo conseguir esto para compilar es haciendo que el constructor de copia tomar una referencia const que es lo que había sospechado. Parece que herb Sutter publicada por algo muy similar a esta en su más reciente GotW. Yo no tratar de replicar la transferencia de la propiedad semántica de std::auto_ptr sin una muy buena razón. Es posible que desee mirar a los diversos objetos valiosos en Boost.SmartPtr . Si es posible, utilice en su lugar.

Si no puede aumentar por cualquier razón, a continuación, leer su aplicación std::auto_ptr favorito y prestar especial atención a la clase std::auto_ptr_ref. Una vez que entienda por qué está allí y exactamente cómo se hace lo que hace, a continuación, volver atrás y escribir una clase de auto-PTR. Esta clase existe para evitar el problema que usted está viendo. IIRC, esto se discute con cierto detalle en Josuttis': La biblioteca estándar de C ++ . Creo que es el que realmente entendí por primera vez.

Otros consejos

Se podría marcar el constructor que toma el argumento T * con la palabra clave "explícita". He verificado que esto funciona y evita la creación del objeto temporal espuria también, una mejora de rendimiento. Cualquier persona que use ese constructor ya no podía basarse en las reglas de conversión de tipo compilador, sin embargo. Por ejemplo, la función cambiará a lo siguiente:

GAutoString Func()
{
    char *s = new char[4];
    strcpy(s, "asd");
    return GAutoString(s);
}

Es molesto, pero no creo que esto es necesariamente algo malo en este caso como conversiones de tipos automáticos pueden ser confusos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top