C ++ fornece uma garantia para a vida útil de uma variável temporária que é criada dentro de uma chamada de função, mas não usada como um parâmetro? Aqui está um exemplo de aula:
class StringBuffer
{
public:
StringBuffer(std::string & str) : m_str(str)
{
m_buffer.push_back(0);
}
~StringBuffer()
{
m_str = &m_buffer[0];
}
char * Size(int maxlength)
{
m_buffer.resize(maxlength + 1, 0);
return &m_buffer[0];
}
private:
std::string & m_str;
std::vector<char> m_buffer;
};
E aqui está como você o usaria:
// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);
std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
Quando o destruidor do objeto StringBuffer temporário será chamado? É isso:
- Antes da chamada para GetString?
- Depois que GetString retornar?
- Depende do compilador?
Eu sei que C ++ garante que uma variável temporária local será válida, desde que haja uma referência a ela - isso se aplica a objetos pai quando há uma referência a uma variável de membro?
Obrigado.
m_str.reserve(maxlength)
emchar * Size(int maxlength)
, caso contrário, o destruidor poderia jogar.Respostas:
O destruidor para esse tipo de temporários é chamado no final da expressão completa. Essa é a expressão mais externa que não faz parte de nenhuma outra expressão. É o seu caso depois que a função retorna e o valor é avaliado. Então, vai funcionar muito bem.
Na verdade, é o que faz os modelos de expressão funcionarem: eles podem manter referências a esse tipo de temporário em uma expressão como
Porque todo temporário vai durar até a expressão
É avaliado completamente. É descrito de forma bastante concisa
12.2 Temporary objects
no Padrão.fonte
printf("%s", strdup(std::string("$$$").c_str()) );
:? Quer dizer, sestrdup(std::string("$$$").c_str())
for considerada a expressão completa, então o ponteiro questrdup
vê é válido . Sestd::string("$$$").c_str()
for uma expressão completa, o ponteiro questrdup
vê é inválido ! Você poderia explicar um pouco mais com base neste exemplo?printf
é a expressão completa. Portanto,strdup
é um vazamento de memória desnecessário - você pode apenas deixá-lo imprimirc_str()
diretamente.a resposta de litb é correta. O tempo de vida do objeto temporário (também conhecido como rvalue) está vinculado à expressão e o destruidor do objeto temporário é chamado no final da expressão completa e quando o destruidor em StringBuffer é chamado, o destruidor em m_buffer também será chamado, mas não o destruidor em m_str, pois é uma referência.
Observe que C ++ 0x muda um pouco as coisas porque adiciona referências rvalue e move a semântica. Essencialmente, usando um parâmetro de referência rvalue (notado com &&), posso 'mover' o rvalue para a função (em vez de copiá-lo) e o tempo de vida do rvalue pode ser vinculado ao objeto para o qual ele se move, não à expressão. Há uma postagem de blog muito boa da equipe do MSVC sobre isso detalhadamente e incentivo as pessoas a lê-la.
O exemplo pedagógico para mover rvalue são strings temporárias e mostrarei a atribuição em um construtor. Se eu tiver uma classe MyType que contém uma variável de membro de string, ela pode ser inicializada com um rvalue no construtor assim:
Isso é bom porque quando eu declaro uma instância desta classe com um objeto temporário:
o que acontece é que evitamos copiar e destruir o objeto temporário e "hello" é colocado diretamente dentro da variável de membro da instância da classe proprietária. Se o objeto for mais pesado do que uma 'string', a cópia extra e a chamada do destruidor podem ser significativas.
fonte
Após o retorno da chamada para GetString.
fonte
StringBuffer está no escopo de GetString. Ele deve ser destruído no final do escopo de GetString (ou seja, quando ele retorna). Além disso, não acredito que C ++ garanta que uma variável existirá enquanto houver referência.
O seguinte deve ser compilado:
fonte
Escrevi quase exatamente a mesma aula:
Antes do padrão, cada compilador fazia isso de maneira diferente. Eu acredito que o antigo Manual de Referência Anotado para C ++ especificava que os temporários deveriam limpar no final do escopo, então alguns compiladores faziam isso. No final de 2003, descobri que o comportamento ainda existia por padrão no compilador Forte C ++ da Sun, então StringBuffer não funcionava. Mas eu ficaria surpreso se algum compilador atual ainda estivesse tão quebrado.
fonte