Pergunta

Eu tenho uma implementação ponteiro auto:

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;

E isso funciona bem no Visual C ++ 6. No entanto, em Visual C ++ 2005 ou 2008 não pode retornar um ponteiro de auto de uma função sem as coisas indo terrivelmente errado.

por exemplo.

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

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

O que acontece é que o compilador cria um GAutoString temporária para armazenar o valor de retorno para a função e, em seguida, de passagem, que a variável 'a' na pilha calles o operador T * () da variável temp, e depois o GAutoPtr (T * ptr = 0) construtor, em vez de apenas usando o construtor de cópia: GAutoPtr (AutoPtrRef p)

Isso resulta na auto ptr temperatura apagar a memória e 'a' segurando um ponteiro para a memória liberada.

No entanto, em VC6 ele faz chamar o construtor direita. Agora em dizer tudo isso eu também usar gcc no Linux e Mac, assim que o código que eu escrevo precisa trabalhar lá também. VC2008 impede que você use um não-const pela variável de valor no construtor de cópia. Também eu não quero "const" de qualquer maneira, porque o construtor de cópia toma posse do bloco de memória que remove a propriedade do objeto que está sendo copiado ... modificando-a.

Como posso fazer este trabalho em VC 2005/2008?

Foi útil?

Solução

Será que esse mesmo compilar sob um g recente ++? Eu tentei no meu MacBook Pro e:

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]’

A única maneira que eu posso chegar a este compilação é fazendo o construtor de cópia tomar uma referência const que é o que eu suspeitava. Parece herb Sutter postou sobre algo muito semelhante a esta no seu mais recente GotW. Eu não iria tentar replicar a transferência de propriedade semântica de std::auto_ptr sem uma razão muito boa. Você pode querer olhar para as várias guloseimas em Boost.SmartPtr . Se possível, usá-los em seu lugar.

Se você não pode aumentar por qualquer motivo, em seguida, ler a sua aplicação favorita std::auto_ptr e uma atenção especial para a classe std::auto_ptr_ref. Depois de entender por que ele está lá e exatamente como ele faz o que faz, e então voltar e escrever uma classe auto-ptr. Esta classe existe para contornar o problema que você está vendo. IIRC, isso é discutido com algum detalhe em Josuttis': A Biblioteca C ++ Padrão . Eu acho que é onde eu realmente entendi pela primeira vez.

Outras dicas

Você pode marcar o construtor que leva o T * discussão com a palavra-chave "explícito". Eu tenho verificado que isso funciona e impede a criação do objeto temporário espúria também, uma melhoria de desempenho. Qualquer pessoa usando esse construtor não podia mais contar com regras de conversão de tipo do compilador, no entanto. Por exemplo, você funcionar mudaria a esta:

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

É chato, mas eu não acho que isso é necessariamente uma coisa ruim neste caso, como conversões de tipo automático pode ser confuso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top