【问题标题】:VS2013 warning C4172 on return Rvalue返回 Rvalue 时 VS2013 警告 C4172
【发布时间】:2015-11-04 08:02:35
【问题描述】:

右值是新的,所以我对此有些怀疑......

VS2013 给出

warning C4172: returning address of local variable or temporary

对于这一行

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

这段代码(如下)是否不可移植和/或在任何地方都有未定义的行为?如果有 - 在哪里以及为什么?难道我做错了什么? 或者这只是 VS2013 编译器的误报警告,在这种特殊情况下我应该把 pragma 忽略它?

temp_value_t 旨在用作级联调用的容器:

[输入值] -> 调用 virtual_func1(temp_value_t) -> 调用 virtual_func2(temp_value_t) -> ... -> 调用 virtual_funcLAST(temp_value_t)

而且 funcLAST 实现知道 temp_value_t 是真正的右值还是左值,所以 funcLAST 知道应该使用哪个函数。

#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... 
*/

【问题讨论】:

    标签: c++ c++11 visual-studio-2013 type-erasure rvalue


    【解决方案1】:

    为什么不存储给定字符串的引用?

    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;
            }
    };
    

    如果您的目标是存储作为右值引用传递的字符串对象,请定义移动构造函数,并将右值字符串本地存储在对象内。

    【讨论】:

    • const 引用也将绑定到一个右值,并且是悬空的。
    • @BoPersson 当独家新闻结束时,右值将消失。我是这个意思。
    • hkBattousai,您的 get_as_temp 实现调用 basic_string(const _Myt& _Right) - 您可以在调试中看到它 - 返回时断点并进入,所以这实际上返回 一个副本 的字符串 - 这真的很糟糕(长操作),因为右值是专门为避免这种情况而设计的功能,而这个副本是右值。我的实现没有这个额外的副本。关于引用 - 引用、指针或 intptr_t 是相同的 - 无论如何类型擦除(类型在类内未知),我只是使用 intptr_t 清楚地显示“类型在类内未知”。
    • 所以“将其转换为 (std::wstring&&) 毫无意义” - 不正确,此转换删除了额外的副本和构造函数调用。
    • "如果你期望一个右值,你不能存储引用。" - 此类 (temp_value_t) 本身不存储,它仅用作函数的参数。此右值引用在调用时不会过期,当调用返回时 - temp_value_t 在右值之前被破坏。
    猜你喜欢
    • 2019-06-15
    • 1970-01-01
    • 2011-04-13
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-05
    • 2015-02-27
    相关资源
    最近更新 更多