Pergunta

Alguém sabe como posso, em código C++ independente de plataforma, impedir que um objeto seja criado no heap?Ou seja, para uma classe "Foo", quero evitar que os usuários façam isso:

Foo *ptr = new Foo;

e apenas permita que eles façam isso:

Foo myfooObject;

Alguém tem alguma idéia?

Saúde,

Foi útil?

Solução

A resposta de Nick é um bom ponto de partida, mas incompleto, pois você realmente precisa sobrecarregar:

private:
    void* operator new(size_t);          // standard new
    void* operator new(size_t, void*);   // placement new
    void* operator new[](size_t);        // array new
    void* operator new[](size_t, void*); // placement array new

(Boas práticas de codificação sugerem que você também sobrecarregue os operadores delete e delete[] - eu faria isso, mas como eles não serão chamados, não é realmente necessário.)

Pauldoo também está correto que isso não sobrevive à agregação em Foo, embora sobreviva à herança de Foo.Você poderia fazer alguma mágica de metaprogramação de modelo para AJUDAR a evitar isso, mas não seria imune a "usuários malvados" e, portanto, provavelmente não vale a pena a complicação.A documentação de como deve ser usado e a revisão do código para garantir que seja usado corretamente são a única maneira de aproximadamente 100%.

Outras dicas

Você poderia sobrecarregar new para Foo e torná-lo privado.Isso significaria que o compilador iria reclamar ...a menos que você esteja criando uma instância de Foo na pilha de dentro de Foo.Para entender esse caso, você simplesmente não poderia escrever o novo método de Foo e então o vinculador reclamaria dos símbolos indefinidos.

class Foo {
private:
  void* operator new(size_t size);
};

PS.Sim, eu sei que isso pode ser facilmente contornado.Na verdade, não estou recomendando - acho uma má ideia - estava apenas respondendo à pergunta!;-)

Não sei como fazer isso de maneira confiável e portátil.mas..

Se o objeto estiver na pilha, você poderá afirmar no construtor que o valor de 'this' está sempre próximo do ponteiro da pilha.Há uma boa chance de que o objeto esteja na pilha, se for esse o caso.

Acredito que nem todas as plataformas implementam suas pilhas na mesma direção, então você pode querer fazer um teste único quando o aplicativo começar para verificar em que direção a pilha cresce.Ou faça alguma brincadeira:

FooClass::FooClass() {
    char dummy;
    ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this);
    if (displacement > 10000 || displacement < -10000) {
        throw "Not on the stack - maybe..";
    }
}

@Usuario

Isso poderia ser contornado criando uma classe que deriva ou agrega Foo.Acho que o que sugiro (embora não seja robusto) ainda funcionaria para classes derivadas e agregadas.

Por exemplo:

struct MyStruct {
    Foo m_foo;
};

MyStruct* p = new MyStruct();

Aqui eu criei uma instância de 'Foo' no heap, ignorando o novo operador oculto de Foo.

Como os cabeçalhos de depuração podem substituir a nova assinatura do operador, é melhor usar o ...assinaturas como uma solução completa:

private:
void* operator new(size_t, ...) = delete;
void* operator new[](size_t, ...) = delete;

Você poderia declarar uma função chamada "operador new" dentro da classe Foo que bloquearia o acesso à forma normal de new.

É esse o tipo de comportamento que você deseja?

Você poderia declará-lo como uma interface e controlar a classe de implementação mais diretamente a partir do seu próprio código.

isso pode ser evitado tornando os construtores privados e fornecendo um membro estático para criar um objeto na pilha

Class Foo
{
    private:
        Foo();
        Foo(Foo& );
    public:
        static Foo GenerateInstance() { 
            Foo a ; return a; 
        }
}

isso fará com que a criação do objeto esteja sempre na pilha.

Não tenho certeza se isso oferece alguma oportunidade em tempo de compilação, mas você já pensou em sobrecarregar o operador 'novo' para sua classe?

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