我一直使用匿名变量,当我不需要为整个当前范围闲置一个命名对象时。
我需要使用一个函数 - 在我的控制之外 - 将指针作为参数并且不进行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
在线编译示例代码以达到同样的效果;所以这个问题不是过时的编译器的限制/错误。
答案 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;
}
引用a
和b
继续引用有效对象。指针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()) );