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

Possible to pass address of anonymous variable?

本文关键字:地址 变量      更新时间:2023-10-16

我一直使用匿名变量,当我不需要在整个当前范围内悬挂命名对象时。

我需要使用一个函数 - 在我的控制之外 - 它将指针作为参数并且不进行 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.

编译器错误非常可读:使用地址运算符需要左值。但我想知道社区是否可以帮助我理解这种限制背后的理由。在我看来,我尝试的使用可能是合理的,因为匿名变量的生存期取决于分号,即它在ptrFunc()的生命周期内是"活着的"。

我考虑过允许指向匿名变量的指针是否被认为是"危险的",因为它们的寿命缩短了。但实际上,如果指针的任何用途 - 即使是对于左值或堆分配的对象也会遇到同样的问题:如果有人挂在任何指针上,它总是有指向无效内存的危险。指针的使用本质上取决于仔细的编码,我认为这个尝试的用例在这方面并没有特别的不同。

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

我还尝试过什么

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

但我想知道社区是否可以帮助我理解这种限制背后的基本原理。在我看来,我尝试的使用可能是合法的,因为匿名变量的生命周期取决于分号,即它在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 相比)语言功能,并且作为一个新的语言功能,使它们不可变没有问题。指针有很多使用它们的现有代码,这些代码会因规则的更改而失效。

最终,您在此处要求的内容不存在,这是有充分理由的:带有地址的值必须位于某个位置,因此具有一定的范围/生存期。要传递给函数的指针是地址。它可以多次读取,当非常量时,可以写入。

编译器不知道调用函数将如何使用您的参数,并希望自由地放置右值,包括将它们折叠到代码中的常量中,或将它们放入寄存器中。你不能把一个地址传递给一个函数。

您所要求的内容似乎简化为编译器糖,它在堆栈上创建一个本地,获取对它的引用,并将其传递给函数,但从代码中隐藏其地址,以便没有其他代码可以使用该值。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.
);

> 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()) );

演示