C++ 它是否有效+;将右值强制转换为常量指针?

C++ 它是否有效+;将右值强制转换为常量指针?,c++,c++11,c++03,C++,C++11,C++03,在匆忙中,需要一个指向对象的指针来传递给函数。我获取了一个未命名的临时对象的地址,让我惊讶的是,它被编译了(原始代码的警告被进一步拒绝,并且缺少下面示例中的const正确性)。出于好奇,我在Visual Studio 2013中设置了一个带有警告的受控环境,并将警告视为错误 考虑以下代码: class Contrived { int something; }; int main() { const Contrived &r = Contrived();

在匆忙中,需要一个指向对象的指针来传递给函数。我获取了一个未命名的临时对象的地址,让我惊讶的是,它被编译了(原始代码的警告被进一步拒绝,并且缺少下面示例中的const正确性)。出于好奇,我在Visual Studio 2013中设置了一个带有警告的受控环境,并将警告视为错误

考虑以下代码:

class Contrived {
  int something;
};

int main() {
  const Contrived &r  = Contrived();                    // this is well defined even in C++03, the object lives until r goes out of scope
  const Contrived *p1 = &r;                             // compiles fine, given the type of r this should be fine. But is it considering r was initialized with an rvalue?
  const Contrived *p2 = &(const Contrived&)Contrived(); // this is handy when calling functions, is it valid? It also compiles
  const int       *p3 = &(const int&)27;                // it works with PODs too, is it valid C++?

  return 0;
}
class Contrived {
  int something;
} globalClass;
int globalPOD = 0;

template <typename T>
void SetGlobal(const T *p, T &global) {
  global = *p;
}

int main() {
  const int *p1 = &(const int&)27;
  SetGlobal<int>(p1, globalPOD);              // does *p still exist at the point of this call?

  SetGlobal<int>(&(const int&)27, globalPOD); // since the rvalue expression is cast to a reference at the call site does *p exist within SetGlobal

  // or similarly with a class
  const Contrived *p2 = &(const Contrived&)Contrived();
  SetGlobal<Contrived>(p2, globalClass);
  SetGlobal<Contrived>(&(const Contrived&)Contrived(), globalClass);

  return 0;
}
三个指针初始化或多或少都是一样的。问题是,这些初始化是C++下的C++有效的,C++ 03,还是两者都有效?考虑到在右值引用方面做了大量工作,我分别询问了C++11以防发生变化。在上面的例子中,分配这些值似乎不值得,但值得注意的是,如果这些值被传递给一个使用常量指针的函数,并且您没有合适的对象,或者您不想在上面的一行上创建一个临时对象,那么这可以节省一些输入

编辑:
根据以上答案,C++03和C++11是有效的。我想就结果对象的生命周期提出一些额外的澄清点

考虑以下代码:

class Contrived {
  int something;
};

int main() {
  const Contrived &r  = Contrived();                    // this is well defined even in C++03, the object lives until r goes out of scope
  const Contrived *p1 = &r;                             // compiles fine, given the type of r this should be fine. But is it considering r was initialized with an rvalue?
  const Contrived *p2 = &(const Contrived&)Contrived(); // this is handy when calling functions, is it valid? It also compiles
  const int       *p3 = &(const int&)27;                // it works with PODs too, is it valid C++?

  return 0;
}
class Contrived {
  int something;
} globalClass;
int globalPOD = 0;

template <typename T>
void SetGlobal(const T *p, T &global) {
  global = *p;
}

int main() {
  const int *p1 = &(const int&)27;
  SetGlobal<int>(p1, globalPOD);              // does *p still exist at the point of this call?

  SetGlobal<int>(&(const int&)27, globalPOD); // since the rvalue expression is cast to a reference at the call site does *p exist within SetGlobal

  // or similarly with a class
  const Contrived *p2 = &(const Contrived&)Contrived();
  SetGlobal<Contrived>(p2, globalClass);
  SetGlobal<Contrived>(&(const Contrived&)Contrived(), globalClass);

  return 0;
}
类设计{
智力的东西;
}全局类;
int globalPOD=0;
模板
void SetGlobal(常量T*p、T&global){
全局=*p;
}
int main(){
常数int*p1=&(常数int&)27;
SetGlobal(p1,globalPOD);//在调用时,*p是否仍然存在?
SetGlobal(&(const int&)27,globalPOD);//由于右值表达式被强制转换为调用站点的引用,因此SetGlobal中是否存在*p
//或者与类类似
常量人工*p2=&(常量人工&)人工();
SetGlobal(p2,globalClass);
SetGlobal(&(const-Contrived&)Contrived(),globalClass);
返回0;
}

问题是对SetGlobal的调用中有一个或两个是有效的,因为它们传递的是一个指向在C++03或C++11标准下调用期间将存在的对象的指针?

第一个是好的:表达式
r
实际上不是一个右值


另外两个在技术上也是有效的,但请注意指针在完整表达式的末尾(分号处)会悬空,任何使用它们的尝试都会显示未定义的行为。右值
是一种表达式,而不是一种对象。我们谈论的是由
artived()
创建的临时对象,说“这个对象是一个右值”是没有意义的。创建对象的表达式是右值表达式,但这是不同的

尽管所讨论的对象是临时对象,但其生存期已延长。使用表示对象的标识符
r
对对象执行操作是完全正确的。表达式
r
是左值


p1
正常。在
p2
p3
行上,引用的生存期在该完整表达式的末尾结束,因此临时对象的生存期也在该点结束。因此,在后续行中使用
p2
p3
将是未定义的行为。初始化表达式可以用作函数调用的参数,如果这是您的意思的话

虽然通过
常量传递右值是完全合法的,但您必须知道,您的代码在
p2
p3
中的指针是无效的,因为它们所指向的对象的生命周期已经结束

举例说明,考虑下面的代码,这些代码通常用于传递临时引用:

template<typename T>
void pass_by_ref(T const&);

请注意,返回值指向的对象只有在使用左值调用此函数时才仍然存在(因为它的参数将变成
typename remove\u reference::type&&&
,即
typename remove\u reference::type&
)。

感谢您的更正。是的,右值指的是表达式而不是对象。这是一个微妙的区别,但我想更准确/准确地说。我没有考虑引用结尾的范围(因为它只是一个演员阵容)。或者我认为对象的生命周期可以再次通过const指针来延长(因为引用只是引擎盖下的一个指针,而引用的定义是为了延长对象的生命周期)。看来情况并非如此?那么,还有一个问题需要澄清。您说过“初始化表达式可以用作函数调用的参数。”那么,我可以这样做吗
void fn(const int*p){global=*p;}
fn(&(const int&)27)
和“object”
p
指向的对象将保证存在于函数中?在语言定义中,引用不是“引擎盖下的指针”。它是变量的别名。事实证明,如果通过引用将参数传递给函数,那么使用变量的地址通常是最简单的方法;但这并没有改变语言定义,它专门讨论了延长生存期的常量引用,而不是指向常量的指针。
rvalue是一种表达式类型
No,rvalue是一种“值类别”。这根本不是一个“类型”,我已经用您的答案已经提到的对象生命周期的这些附加点更新了我的问题,并更正了右值术语。使用的术语与ReValk中的值类别或表达式定义相匹配,在这里的注释中仍在讨论。如果函数用RValt临时调用,则它无效C++,因为它不接受R值的地址。