C++ 是否可以传递匿名变量的地址?
我一直使用匿名变量,当我不需要在整个当前范围内挂起命名对象时 我需要使用一个不受我控制的函数,该函数将指针作为参数,并且不进行空检查。我希望能够传递匿名变量的地址(因为我不关心在解引用地址中写入的值),但遇到编译错误。下面的简化示例C++ 是否可以传递匿名变量的地址?,c++,pointers,anonymous,lvalue,C++,Pointers,Anonymous,Lvalue,我一直使用匿名变量,当我不需要在整个当前范围内挂起命名对象时 我需要使用一个不受我控制的函数,该函数将指针作为参数,并且不进行空检查。我希望能够传递匿名变量的地址(因为我不关心在解引用地址中写入的值),但遇到编译错误。下面的简化示例 #include <iostream> void ptrFunc( const int* p ) { if ( p ) { std::cout << "*p == " << *p << std::en
#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.
}
编译器错误可读性很强:使用address运算符需要左值。但我想知道社区能否帮助我理解这一限制背后的理由。在我看来,我的尝试使用可能是合法的,因为匿名变量的生存期长达分号,即它在ptrFunc()
的生存期内是“活动的”
我考虑了允许指针指向匿名变量是否被认为是“危险的”,因为它们的使用寿命缩短了。但实际上,如果指针的任何用途——即使是左值或堆分配的对象——都会遇到相同的问题:如果有人挂在任何指针上,它总是有指向无效内存的危险。指针的使用本质上依赖于仔细的编码,我不认为这个尝试过的用例在这方面有什么特别的不同
我很想了解这背后的原因。多谢各位
我还试过什么
尝试使用
gcc-4.9.2
在线编译示例代码,效果相同;因此,这个问题不是来自过时编译器的限制/缺陷。最终,您在这里要求的内容并不存在,原因很好:带有地址的值必须位于某个位置,因此具有一定的作用域/生存期。传递给函数的poiner是地址。它可以多次读取,非常量时可以写入
编译器不知道调用函数将如何使用您的参数,并且希望能够自由地放置右值,包括将它们折叠成代码中的常量,或者将它们放入寄存器。您不能将地址传递给该函数并将其传递给函数
您所要求的似乎简化为编译器糖,编译器糖在堆栈上创建一个本地值,获取对它的引用,并将其传递给函数,但对代码隐藏其地址,以便其他代码不能使用该值。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(常数int*p)
{
如果(p)
{
std::coutC++11引入了获取变量地址的方法,即使它是重写运算符&
的类类型。您可以应用类似的技术获取临时变量的地址,例如:
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()) );
模板
常数T*addrtemp(常数T和参数)
{
返回重新解释\u cast(
&康斯特卡斯特(
重新解释铸造(arg)
)
);
}
ptrFunc(addrtemp(int());
但我想知道社区是否能帮助我理解这一限制背后的基本原理。在我看来,我尝试的使用可能是合法的,因为匿名变量的生存期达到分号,即它在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;
}
intmain(){
常数int&a=1;
int&b=2;
const int*c=&static_cast(3);//不要这样做
返回a+b-*c;
}
引用a
和b
继续引用有效对象。指针c
不引用有效对象,并且生命周期扩展规则无法合理地适用于指针,而指针的基本内容没有重大变化。引用是可行的,因为引用是新的(与c相比)语言特性,并且作为一种新的语言特性,使它们不可变是没有问题的。指针有许多使用它们的现有代码,这些代码会因规则的更改而失效“编译器…想要自由地放置右值,包括将它们折叠成代码中的常量,或将它们放入寄存器。你不能将地址传递给函数。”让我看看我是否理解正确:右值(如我的匿名变量)可以由编译器放在寄存器中(因为它是常量),编译器不允许获取寄存器的地址。是这样吗?MSVC有一个奇怪的语言扩展来支持这种事情。例如,第475行at(Frank Luna的代码,不是我的代码)。这在和FWIW中进行了讨论,解决该限制并不太困难。您可以使用lambda函数作为对ptrFunc
调用的包装器。例如:[](int i){ptrFunc(&i);}(int())
@RSahu很聪明,但在这个开发环境中我一直使用C++98。你用@EyasSH的答案解决了我一夜之间遇到的一个问题,但也值得提出你的答案:引用实际上是隐藏在引擎盖下的指针,在它们上面加上语法糖以消除对引用的取消引用。既然如此,为什么会有这样的问题指针和引用的不同生存期扩展规则?这就是“语言本身”吗?也许还值得问我以前的问题:Eyash的答案(我认为他在这个问题上不再活跃):既然指针和引用是相同的“隐藏”,如果编译器想在寄存器中放置常量的话(Eyash说获取寄存器地址是非法的:真的吗?),那么为什么该寄存器地址被引用还是被指针引用在合法性上有区别呢?“引用实际上是隐藏的指针”——不总是这样。这是区别之一。
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()) );
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;
}