【问题标题】:How can I take the address of a temporary/rvalue for copying?如何获取临时/右值的地址进行复制?
【发布时间】:2017-06-13 20:34:54
【问题描述】:

我打开了一个要写入的 ofstream 文件,我想写入一个无符号整数的 4 个字节。我希望 int 为零,所以我尝试这样做:

outFile.write((char*)&unsigned int(0), sizeof(unsigned int));  // Expression must be an lvalue

unsigned int a = 0;
outFile.write((char*)&a, sizeof(unsigned int));         // This works fine

我的理解是,像 unsigned int 这样的东西的生命周期直到该行的末尾,换句话说,被下一个分号破坏。 是通过预先创建本地来编写这样的东西的唯一方法吗?另外,我注意到 fstreams 采用 char 指针,我想知道在复制内容时是否需要谨慎,例如在二进制模式下,我希望它完全按照内存中的方式写入字节,但是例如,如果我有一个 unsigned int 255 它会按原样复制这个无符号整数位吗?在处理原始内存复制时,这不应该是一个空指针吗?

【问题讨论】:

    标签: c++ file io fstream


    【解决方案1】:

    局部变量在超出范围时被销毁。这通常在下一个右大括号处。

    outFile.write((char*)&unsigned int(0)
    

    正在尝试获取不存在的东西的地址。你必须先实例化变量

    {
      ....code...
      {
        unsigned int a = 0;
        outFile.write((char*)&a, sizeof(unsigned int));
      }
      <- legally a no longer exists
      unsigned int b = 0; // b *might* now occupy the same stack space that was used to store a.  then again it might not, it depends on the compiler.
    }
    <- b no longer exists.
    

    您可以使用非正统的方法来访问超出范围的局部变量,具体取决于编译器如何构建堆栈框架,先前由所述局部占用的空间可能会或可能不会被现在活动的东西使用。

    outFile.write((char*)&a, sizeof(unsigned int));
    

    将尝试写入与 unsigned int 一样多的位,逐位写入。

    但我会使用

    outFile.write((char*)&a, sizeof(a));
    

    因为硬编码大小可能会在以后让您头疼。如果您将 a 的数据类型更改为 double,但您忘记将 sizeof 更新为 sizeof(double)

    【讨论】:

    • 我认为它确实存在,但获取 &unsigned int(0) 的地址就可以了,因为它直到该行之后才会超出范围,我想。我只是想找出一种方法来避免本地并将其写在它的位置,会很棒。
    • &unsigned int(0) 试图获取数据类型的地址,而不是该类型的变量。 &unsigned int(0) 实际上并没有在内存中创建任何东西,这就是编译器抱怨的原因。
    • @TitoneMaurice 它确实存在,但你不能取它的地址
    • @CascadeCoder unsigned int(0)unsigned int 类型的值。它不是“数据类型”。它可能会在内存中创建一些东西
    • @mm 那么为什么 sizeof(unsigned int(0)) 会产生编译器错误。但是,sizeof((unsigned int)0) 的大小肯定...
    【解决方案2】:

    定义一个变量(左值)是访问int unsigned int a = 0;内存的唯一方法

    右值可能永远不会存在于内存中

    (3 + 4) 可以在编译时优化为 7

    以下是一些差异示例

    Difference between rvalue and lvalue

    在不编码的情况下导出整数时应该小心

    This question explains some of the pitfalls of writing the raw bytes of an int

    【讨论】:

    • 这个答案误用了“左值”和“右值”这两个表达类别。 (您链接到的 MSDN 页面也犯了同样的错误)。在前两句中,您实际上分别指的是“变量”和“临时对象”。此外,临时对象可能存在于内存中。
    • @jamollenkamp int n; int &amp;&amp;r = move(n); move() 表达式是内存中存在的右值示例
    【解决方案3】:

    您不能获取右值的地址,除非它被强制转换为左值。然后编译器会创建一个临时变量并获取它的地址。

    template<typename T>
    remove_reference_t<T>& rtolvalue_cast(remove_reference_t<T> &&t)
    {
        return static_cast<remove_reference_t<T> &>(t);
    }
    

    那么你可以写:

    outFile.write((char*)& rtolvalue_cast<unsigned int>(0), sizeof(unsigned int));
    

    从技术上讲,这个演员表与std::forward&lt;T&gt; 是一个遥远的亲戚,它也可以做到这一点,除了它在图书馆中被static_assert 禁用,这可能是有充分理由的。 这个演员阵容更像是一个技术人工制品,而不是现实的东西。

    相反,创建一个临时变量并获取其地址。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-05
      • 2013-06-05
      相关资源
      最近更新 更多