可以传递匿名变量的地址吗?

时间:2017-03-24 01:46:50

标签: c++ pointers anonymous lvalue

我一直使用匿名变量,当我不需要为整个当前范围闲置一个命名对象时。

我需要使用一个函数 - 在我的控制之外 - 将指针作为参数并且不进行NULL检查。我希望能够传递一个匿名变量的地址(因为我不关心在解除引用的地址写的值),但是遇到编译错误。以下简化示例......

#include <iostream>

void ptrFunc( const int* p )
{
  if ( p )
  {
    std::cout << "*p == " << *p << std::endl;
  }
}

void refFunc( const int& i )
{
  std::cout << "(ref)i == " << i << std::endl;
}

void valueFunc( int i )
{
  std::cout << "i == " << i << std::endl;
}

int main( int argc, char* argv[] )
{
  valueFunc( int() );   // This is fine.
  refFunc( int() );     // This is also fine.
  ptrFunc( &(int()) );  // This doesn't compile.
}

...生成此编译错误:

>g++ -g main.cpp 
main.cpp: In function 'int main(int, char**)':
main.cpp:25:19: error: lvalue required as unary '&' operand
   ptrFunc( &(int()) );  // This doesn't compile.
                   ^
>g++ --version
g++ (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

编译器错误非常易读:使用地址运算符需要左值。但我想知道社区是否可以帮助我理解这种限制背后的基本原理。我似乎似乎我尝试使用可能合理合法,因为匿名变量的生命周期取决于分号,即它是&#34; alive&#34;在ptrFunc()的生命期内。

我考虑过它是否被认为是危险的&#34;允许指向匿名变量的指针,因为它们缩短了生命周期。但是,如果指针 - 甚至对于左值或堆分配的对象 - 也会遇到同样的问题:如果有人挂在任何指针上,那么它总是存在可能指向无效内存的危险。指针的使用本质上取决于仔细的编码,我不认为这种尝试的用例在这方面特别不同。

我很想知道这背后的理由。谢谢。

我还尝试了什么

尝试使用gcc-4.9.2在线编译示例代码以达到同样的效果;所以这个问题不是过时的编译器的限制/错误。

3 个答案:

答案 0 :(得分:1)

最终你在这里要求的东西并不存在是有充分理由的:带地址的值必须位于某处,因此具有一定的范围/生命周期。您将传递给函数的poiner是一个地址。它可以多次读取,并且,当非常量时,写入。

编译器不知道调用函数将如何使用您的参数,并且希望自由地放置rvalues,包括将它们折叠成代码中的常量,或者将它们放在寄存器中。您无法获取地址并将其传递给函数。

您要求的似乎是减少编译器糖,在堆栈上创建一个本地,引用它,并将其传递给一个函数,但隐藏其代码的地址,以便没有其他代码可以使用该值。 C ++建立在显式内存管理之上,因此与之相反。

好的,但我真的想这样做

但是,为了好玩,我认为你可以这样做:

#include <memory>
#include <iostream>

void ptrFunc( const int* p )
{
  if ( p )
  {
    std::cout << "*p == " << *p << std::endl;
  }
}

int main()
{
  ptrFunc(std::unique_ptr<int>(new int()).get());
  return 0;
}

这是如何工作的?

非常好,因为效率非常低。从语法上讲,它可以满足您的需求:

ptrFunc(                 // 1. call ptrFunc
  std::unique_ptr<int>(  // 2. instantiate a unique_ptr as a temporary
                         //    this takes a pointer to a heap-allocated value
                         //    and assumes ownership of it. it deletes that
                         //    value when it goes out of scope. for a
                         //    temporary, this happens after the expression.
    new int()            // 3. heap-allocate an integer
  ).get()                // 4. returns a raw-pointer to the heap-allocated
                         //    value owned by the unique_ptr. That value
                         //    becomes invalid memory if accessed after the
                         //    unique_ptr destroys it.
);

答案 1 :(得分:1)

  

但我想知道社区是否可以帮助我理解这种限制背后的理由。我似乎似乎我尝试使用可能合理合法,因为匿名变量的生命周期取决于分号,即它是&#34; alive&#34;在ptrFunc()的生命期内。

在这种情况下,是的,它会起作用。一般来说,没有。

引用会导致临时生命周期延长。指针不是。那就是:

int main() {
    const int & a = 1;
    int && b = 2;
    const int * c = &static_cast<const int &>(3); // don't do this
    return a + b - *c;
}

引用ab继续引用有效对象。指针c没有,并且没有合理的方式,生命周期扩展规则可以用于指针而没有指针的重大根本变化。它可以用于引用,因为引用是一种新的(与C语言相比)语言特性,并且作为一种新的语言特性,使它们不可变是没有问题的。指针有很多使用它们的现有代码,这些代码会因规则的变化而失效。

答案 2 :(得分:0)

C ++ 11引入std::addressof()来获取变量的地址,即使它是覆盖operator&的类类型。您可以应用类似的技术来获取临时变量的地址,例如:

template <class T>
const T* addrtemp(const T& arg)     
{    
    return reinterpret_cast<T*>(    
        &const_cast<char&>(    
            reinterpret_cast<const volatile char&>(arg)
        )
    );    
}

ptrFunc( addrtemp(int()) );

Demo