Pergunta

Eu vi uma classe que é uma classe que é definido como este ..

class StringChild : public StringBase
    {
public:
    //some non-virtual functions
    static StringChild* CreateMe(int size);
private:
    unsigned char iBuf[1];
    };

A função de fábrica estático tem a seguinte implementação ..

return new(malloc(__builtin_offsetof(StringChild ,iBuf[size]))) StringChild();

Assim, tanto quanto eu entendo que esta função é usando posicionamento novo para estender essa classe.

É seguro só porque há apenas 1 membro e é alocado no heap?

Foi útil?

Solução

É um truque C velho que foi usado para trabalho em torno da não-availablity de matrizes de comprimento variável na planície C. Sim, ele também funciona em C ++, enquanto você usar construções alocador adequados (como alocar um monte de memória bruta do tamanho desejado e, em seguida, a colocação newing o objecto lá). É seguro, desde que você não caminhar sobre o final da memória alocada, mas tende a confundir pelo menos alguns depuradores de memória.

Uma coisa que você tem que fazer absolutamente certo ao usar esta técnica é que a matriz de comprimento variável é o último elemento no layout do objeto, caso contrário você vai andar sobre outras variáveis ??internas.

Mas estou um pouco duvidoso sobre a implementação da função de fábrica - Presumo que o parâmetro 'tamanho' é na verdade o tamanho da matriz desejada? Além disso, não se esqueça que você tem que liberar a memória acima usando 'livre' e não 'delete', embora o último trabalho poder na maioria dos casos.

A menos que haja uma razão convincente de por que a memória tem de ser gerida desta forma, eu simplesmente substituir a matriz com um std :: vector.

Outras dicas

Esta deve ser OK para PODs fornecido iBuf é o último membro da estrutura. Os problemas com os não-pods poderia ser que, por exemplo. compilador é livre para / membros reordenar públicas / privadas protegidas, classes base virtuais acabam no final do objeto mais derivado IIUC, etc.

A sua estrutura é não-POD (tem uma classe base) para que eu não recomendo.

Além disso, se você criar instâncias como esta

return new(malloc(__builtin_offsetof(StringChild ,iBuf[size]))) StringChild();

Você deve certificar-se de que a memória adquirida pelo malloc deve ser liberado com graça, então apagar suas instâncias como esta:

obj->~StringChild();
free(obj);

Talvez você gostaria de usar ::operator new() para alocação

A rigor, desde StringChild é derivado de StringBase não é seguro. O padrão C ++ não especifica o layout para subobjects classe base. Cláusula 10 § 3º:

A ordem em que os sub-objectos de classe base são atribuídos do objeto mais derivado (1,8) não é especificado.

Se StringChild fosse um struct POD, então essa técnica um seria seguro.

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