new operador (C++)

Tenta alocar e inicializar um objeto ou matriz de objetos de um tipo especificado ou de espaço reservado e retorna um ponteiro diferente de zero com tipo adequado para o objeto (ou para o objeto inicial da matriz).

Sintaxe

new-expression:
::optnewnew-placementoptnew-type-idnew-initializeropt
::optnewnew-placementopt(type-id)new-initializeropt

new-placement:
( expression-list )

new-type-id:
type-specifier-seqnew-declaratoropt

new-declarator:
ptr-operatornew-declaratoropt
noptr-new-declarator

noptr-new-declarator:
[expression]attribute-specifier-seqopt
noptr-new-declarator[constant-expression]attribute-specifier-seqopt

new-initializer:
(expression-listopt)
braced-init-list

Comentários

Se for malsucedido, new retorna zero ou lança uma exceção. Para obter mais informações, confira Operadores new e delete. Você pode alterar esse comportamento padrão escrevendo uma rotina de manipulação de exceção personalizada e chamando a função _set_new_handler da biblioteca em tempo de execução com o nome da sua função como argumento.

Para obter informações sobre como criar um objeto no heap gerenciado em C++/CLI e C++/CX, confira gcnew.

Observação

As Extensões de Componentes do Microsoft C++ (C++/CX) fornecem suporte para a palavra-chave new a fim de adicionar entradas de slot a vtable. Para obter mais informações, confira new (novo slot na vtable)

Quando new é usado para alocar memória para um objeto de classe do C++, o construtor do objeto é chamado após a memória ser alocada.

Use o operador delete para desalocar a memória alocada com o operador new. Use o operador delete[] para excluir uma matriz alocada pelo operador new.

O exemplo a seguir aloca e depois libera uma matriz bidimensional de caracteres de tamanho dim por 10. Ao alocar uma matriz multidimensional, todas as dimensões, exceto a primeira, devem ser expressões de constantes que são avaliadas como valores positivos. A dimensão mais à esquerda da matriz pode ser qualquer expressão que seja avaliada como um valor positivo. Ao alocar uma matriz usando o operador new, a primeira dimensão pode ser zero; o operador new retorna um ponteiro exclusivo.

char (*pchar)[10] = new char[dim][10];
delete [] pchar;

O type-id não pode conter const, volatile, declarações de classe nem declarações de enumeração. A seguinte expressão é mal formada:

volatile char *vch = new volatile char[20];

O operador new não aloca tipos de referência porque eles não são objetos.

O operador new não pode ser usado para alocar uma função, mas pode ser usado para alocar ponteiros para funções. O exemplo a seguir aloca e depois libera uma matriz de sete ponteiros para funções que retornam inteiros.

int (**p) () = new (int (*[7]) ());
delete p;

Se você usar o operador new sem nenhum argumento extra e o compilar com a opção /GX, /EHa ou /EHs, o compilador gera um código para chamar o operador delete caso o construtor lance uma exceção.

A lista a seguir descreve os elementos de gramática de new:

new-placement
Fornece uma maneira de passar argumentos extras se você sobrecarregar new.

type-id
Especifica o tipo a ser alocado; pode ser um tipo definido pelo usuário ou interno. Se a especificação de tipo for complicada, poderá ficar entre parênteses para forçar a ordem de associação. O tipo pode ser um espaço reservado (auto) cujo tipo é determinado pelo compilador.

new-initializer
Fornece um valor para o objeto inicializado. Não é possível especificar inicializadores para matrizes. O operador new só criará matrizes de objetos se a classe tiver um construtor padrão.

noptr-new-declarator
Especifica os limites da matriz. Ao alocar uma matriz multidimensional, todas as dimensões, exceto a primeira, devem ser expressões de constantes que são avaliadas como valores positivos conversíveis para std::size_t. A dimensão mais à esquerda da matriz pode ser qualquer expressão que seja avaliada como um valor positivo. Aplica-se attribute-specifier-seq ao tipo de matriz associado.

Exemplo: alocar e liberar uma matriz de caracteres

O exemplo de código a seguir aloca uma matriz de caracteres e um objeto da classe CName e depois os libera.

// expre_new_Operator.cpp
// compile with: /EHsc
#include <string.h>

class CName {
public:
   enum {
      sizeOfBuffer = 256
   };

   char m_szFirst[sizeOfBuffer];
   char m_szLast[sizeOfBuffer];

public:
   void SetName(char* pszFirst, char* pszLast) {
     strcpy_s(m_szFirst, sizeOfBuffer, pszFirst);
     strcpy_s(m_szLast, sizeOfBuffer, pszLast);
   }

};

int main() {
   // Allocate memory for the array
   char* pCharArray = new char[CName::sizeOfBuffer];
   strcpy_s(pCharArray, CName::sizeOfBuffer, "Array of characters");

   // Deallocate memory for the array
   delete [] pCharArray;
   pCharArray = NULL;

   // Allocate memory for the object
   CName* pName = new CName;
   pName->SetName("Firstname", "Lastname");

   // Deallocate memory for the object
   delete pName;
   pName = NULL;
}

Exemplo: operador new

Se você usar o formato de posicionamento do operador new (o formato com mais argumentos do que tamanho), o compilador não dará suporte ao formato de posicionamento do operador delete caso o construtor lance uma exceção. Por exemplo:

// expre_new_Operator2.cpp
// C2660 expected
class A {
public:
   A(int) { throw "Fail!"; }
};
void F(void) {
   try {
      // heap memory pointed to by pa1 will be deallocated
      // by calling ::operator delete(void*).
      A* pa1 = new A(10);
   } catch (...) {
   }
   try {
      // This will call ::operator new(size_t, char*, int).
      // When A::A(int) does a throw, we should call
      // ::operator delete(void*, char*, int) to deallocate
      // the memory pointed to by pa2.  Since
      // ::operator delete(void*, char*, int) has not been implemented,
      // memory will be leaked when the deallocation can't occur.

      A* pa2 = new(__FILE__, __LINE__) A(20);
   } catch (...) {
   }
}

int main() {
   A a;
}

Inicializando objetos alocados com new

Um campo opcional new-initializer é incluído na gramática do operador new. Esse campo permite que os novos objetos sejam inicializados com construtores definidos pelo usuário. Para obter mais informações sobre como a inicialização é feita, confira Inicializadores. O exemplo a seguir ilustra como usar uma expressão de inicialização com o operador new:

// expre_Initializing_Objects_Allocated_with_new.cpp
class Acct
{
public:
    // Define default constructor and a constructor that accepts
    //  an initial balance.
    Acct() { balance = 0.0; }
    Acct( double init_balance ) { balance = init_balance; }
private:
    double balance;
};

int main()
{
    Acct *CheckingAcct = new Acct;
    Acct *SavingsAcct = new Acct ( 34.98 );
    double *HowMuch = new double { 43.0 };
    // ...
}

Neste exemplo, o objeto CheckingAcct é alocado usando o operador new, mas nenhuma inicialização padrão é especificada. Assim, o construtor padrão da classe, Acct(), é chamado. O objeto SavingsAcct é então alocado da mesma maneira, mas ele é inicializado explicitamente como 34,98. Como 34,98 é do tipo double, o construtor que usa um argumento desse tipo é chamado para manipular a inicialização. Por fim, o tipo sem classe HowMuch é inicializado como 43,0.

Se um objeto for de um tipo de classe e essa classe tiver construtores (como no exemplo anterior), o objeto só poderá ser inicializado pelo operador new se uma destas condições for atendida:

  • Os argumentos fornecidos no inicializador concordam com os argumentos de um construtor.

  • A classe tem um construtor padrão (um construtor um que pode ser chamado sem argumentos).

Inicialização explícita por elemento não pode ser feita ao alocar matrizes usando o operador new. Somente o construtor padrão, caso exista, será chamado. Para obter mais informações, confira Argumentos padrão.

Se a alocação de memória falhar (operator new retorna um valor de 0), nenhuma inicialização será realizada. Esse comportamento protege contra tentativas de inicialização de dados que não existem.

Assim como acontece com as chamadas de função, a ordem em que as expressões inicializadas são avaliadas não está definida. Além disso, você não deve confiar que essas expressões serão totalmente avaliadas antes que ocorra a alocação da memória. Se a alocação de memória falhar e o operador new retornar zero, algumas expressões no inicializador poderão não ser avaliadas completamente.

Tempo de vida de objetos alocados com new

Os objetos alocados com o operador new não são destruídos quando o escopo em que são definidos é fechado. Como o operador new retorna um ponteiro para os objetos que ele atribui, o programa deve definir um ponteiro com escopo apropriado para acessar e excluir esses objetos. Por exemplo:

// expre_Lifetime_of_Objects_Allocated_with_new.cpp
// C2541 expected
int main()
{
    // Use new operator to allocate an array of 20 characters.
    char *AnArray = new char[20];

    for( int i = 0; i < 20; ++i )
    {
        // On the first iteration of the loop, allocate
        //  another array of 20 characters.
        if( i == 0 )
        {
            char *AnotherArray = new char[20];
        }
    }

    delete [] AnotherArray; // Error: pointer out of scope.
    delete [] AnArray;      // OK: pointer still in scope.
}

Uma vez que o ponteiro AnotherArray sai do escopo no exemplo, o objeto não pode mais ser excluído.

Como funciona new

A new-expression (a expressão que contém o operador new) faz três coisas:

  • Localiza e reserva o armazenamento para que o objeto ou objetos sejam alocados. Quando essa fase for concluída, a quantidade correta de armazenamento é alocada, mas ela ainda não é um objeto.

  • Inicializa o(s) objeto(s). Após a conclusão da inicialização, informações suficientes estão presentes para que o armazenamento alocado seja um objeto.

  • Retorna um ponteiro para objeto(s) do tipo de ponteiro derivado de new-type-id ou type-id. O programa usa esse ponteiro para acessar o objeto recentemente alocado.

O operador new invoca a função operator new. Para matrizes de qualquer tipo e para objetos que não forem dos tipos class, struct ou union, uma função global, ::operator new, é chamada para alocar o armazenamento. Os objetos de tipo de classe podem definir sua própria função de membro estático operator new em uma base por classe.

Quando o compilador encontrar o operador new para atribuir um objeto de tipo T, ele emite uma chamada para T::operator new( sizeof(T) ). Ou então, se nenhum operator new definido pelo usuário estiver definido, ::operator new( sizeof(T) ). Portanto, o operador new pode alocar a quantidade de memória correta para o objeto.

Observação

O argumento para operator new é do tipo std::size_t. Este tipo é definido em <direct.h>, <malloc.h>, <memory.h>, <search.h>, <stddef.h>, <stdio.h>, <stdlib.h>, <string.h> e <time.h>.

Uma opção na gramática permite a especificação de new-placement (confira a gramática do new operador). O parâmetro de new-placement pode ser usado apenas para implementações definidas pelo usuário de operator new; ele permite que as informações adicionais sejam passadas para operator new. Uma expressão com um campo new-placement, como T *TObject = new ( 0x0040 ) T;, é traduzida como T *TObject = T::operator new( sizeof( T ), 0x0040 ); se a classe T tiver o membro operator new. Caso contrário, como T *TObject = ::operator new( sizeof( T ), 0x0040 );.

A intenção original do campo new-placement era permitir que os objetos dependentes de hardware fossem alocados a endereços especificados pelo usuário.

Observação

Embora o exemplo anterior mostre apenas um argumento no campo new-placement, não há nenhuma limitação para o número de argumentos adicionais que podem ser passados para operator new dessa maneira.

Mesmo quando operator new tiver sido definido para um tipo de classe T, você pode usar o operador global new explicitamente, como neste exemplo:

T *TObject = ::new TObject;

O operador de resolução do escopo (::) força o uso do operador global new.

Confira também

Expressões com operadores unários
Palavras-chave
new e delete operadores