2015-11-04 3 views
1

rvalues ​​sont nouveaux, donc j'avoir des doutes à son sujet ...C4172 d'avertissement de VS2013 sur le retour rvalue

VS2013 donne

warning C4172: returning address of local variable or temporary 

pour cette ligne

return (std::wstring&&)   (*(std::wstring*)v); 

Est-ce code (ci-dessous) nonportable et/ou ont un comportement indéfini partout? S'il y a - où et pourquoi? Est-ce que je fais quelque chose de mal? Ou c'est juste un avertissement faussement positif du compilateur VS2013, et je devrais juste mettre pragma pour l'ignorer dans ce cas particulier?

temp_value_t vise à utiliser comme un conteneur pour une cascade d'appels:

[valeur typée] -> Appels virtual_func1 (temp_value_t) -> Appels virtual_func2 (temp_value_t) -> ... -> Appels virtual_funcLAST (temp_value_t)

et l'implémentation de funcLAST sait si temp_value_t est vraiment rvalue ou lvalue, donc funcLAST sait quelle fonction doit être utilisée.

#include "stdafx.h" 

class temp_value_t 
    { 
    private: 
     intptr_t v; 
    public: 
     temp_value_t(const std::wstring& s) 
      { 
      v = (intptr_t)&s; 
      }; 

     temp_value_t(std::wstring&& s) 
      { 
      v = (intptr_t)&s; 
      }; 

     std::wstring&& get_as_temp() 
      { 
      return (std::wstring&&)   (*(std::wstring*)v); 
      }; 

     const std::wstring& get_as_const() 
      { 
      return (const std::wstring&) (*(std::wstring*)v); 
      }; 
    }; 

void test(temp_value_t v, bool is_param_const) 
    { 
    std::wstring s; 

    if(is_param_const) 
     s = v.get_as_const(); 
    else 
     s = v.get_as_temp(); 

    std::wcout << L"Inner = '" << s << L"'\n"; 
    }; 

int _tmain(int argc, _TCHAR* argv[]) 
    { 
    { 
    std::wcout << L"Test with temp:\n"; 
    std::wstring s(L"abc"); 
    test(s, false); 
    std::wcout << L"Outer = '" << s << L"'\n"; 
    } 

    std::wcout << L"\n\n"; 

    { 
    std::wcout << L"Test with const:\n"; 
    std::wstring s(L"abc"); 
    test(s, true); 
    std::wcout << L"Outer = '" << s << L"'\n"; 
    } 

    return 0; 
    } 

/* 
VS2013 results: 
    Test with temp: 
    Inner = 'abc' 
    Outer = '' 


    Test with const: 
    Inner = 'abc' 
    Outer = 'abc' 

So all works fine... 
*/ 

Répondre

0

Pourquoi ne stockez-vous pas une référence de la chaîne donnée?

class temp_value_t 
{ 
    private: 
     const std::wstring & v; 
    public: 
     temp_value_t(const std::wstring & s) 
      : v(s) 
     { 
     } 

     // You can't store reference if you are expecting an rvalue. 
     // Because, that rvalue is going to or may expire soon, 
     // and when that happens, the stored reference will be invalid. 
     //temp_value_t(std::wstring && s) 
     // : v(std::move(s)) 
     //{ 
     //} 

     // This will already return an rvalue. 
     // It is meaningless to cast it to (std::wstring&&). 
     std::wstring get_as_temp() 
     { 
      return v; 
     } 

     const std::wstring & get_as_const() 
     { 
      return v; 
     } 
}; 

Si vous le but est de stocker un objet de chaîne qui est passée comme une référence rvalue, définir un constructeur de déplacer et de stocker la chaîne rvalue localement dans l'objet.

+0

La référence const va également se lier à un rvalue, et sera tout aussi pendante. –

+0

@BoPersson La valeur disparaîtra à la fin de la récupération. Je voulais dire ça. – hkBattousai

+0

hkBattousai, votre implémentation de get_as_temp appelle basic_string (const _Myt & _Right) - vous pouvez le voir dans debug - breakpoint au retour et entrer dans, donc ceci, en fait, renvoie ** une copie ** d'une chaîne - ** qui est vraiment mauvais (opération longue), car rvalue est une fonctionnalité spécialement conçue pour éviter cela **, et cette copie est rvalue. Ma mise en œuvre n'a pas cette copie supplémentaire. A propos de reference - reference, pointer ou intptr_t est identique pour ce type - effacement de toute façon (le type n'est pas connu en classe), j'ai juste utilisé intptr_t pour montrer clairement "type is unknown in class". –