C ++ const引用成员延长对象的生命周期

时间:2011-08-05 11:12:02

标签: c++

这与a question posted yesterday有关。

class A
{
public:
    mutable int x;
   A()  
   { 
      static int i = 0; 
      x = i; 
      i++;  
      std::cout << " A()" << std::endl; 
   }
   ~A() 
   { 
       std::cout << "~A()" << std::endl; 
   }
   void foo() const 
   { 
       x = 1; 
   };
};

class B
{
public:
   const A & a;
   B(const A & a) : a(a) 
   { 
       std::cout << " B()" << std::endl; 
   }
   ~B() 
   { 
       std::cout << "~B()" << std::endl; 
   }
   void doSomething() 
   { 
       a.foo(); 
   };
};

int main() 
{
   B b((A()));
   b.doSomething();
}

现在,在调用doSomething之前调用了析构函数。但是,虽然该函数基本上更改了A的成员,但调用仍然有效。它是不是同一个实例。没有其他A创建。我使用A的构造函数中的静态来跟踪它。谁能解释一下?

4 个答案:

答案 0 :(得分:6)

这是未定义的行为,因此没有语言标准解释。

然而,A的析构函数对存储x的内存区域没有任何作用,所以如果你稍后看一下该值可能仍然存在。或者,如果您尝试写入地址,地址仍然存在。你不能这样做。

答案 1 :(得分:0)

  • 在~A()之后您的引用无效且未定义行为
  • ~A()另外调用A的所有成员的析构函数

以此为例

    class B
    {
    public:
            const std::string & a;
            B(const std::string & a) : a(a) 
            { 
                    std::cout << " B()" << std::endl; 
            }
            ~B() 
            { 
                    std::cout << "~B()" << std::endl; 
            }
            void doSomething() 
            { 
                    std::cout << "a = " << a << std::endl; 
            };
    };

    int main() 
    {
            B b(std::string("I love C++ so much!"));
            b.doSomething();
    }

答案 2 :(得分:0)

博是正确的。

此外,您可以检查存储“A”的地址,并确认该地址尚未被重用(请记住析构函数释放(“释放”)内存,但不会t遍历数据结构,将所有位设置回0;这将是低效的。)

例如,如果您发现A存储在堆栈顶部,那么您很幸运,您的后续函数调用未传入参数,因为这会覆盖A的内存区域。

答案 3 :(得分:0)

扩大Bo的答案。

对于临时存在,将在堆栈上保留空间。只要语义要求临时存在,这个空间实际上是保留的,然后可以重用其他东西。

如果你在重用后尝试使用内存,你会发现一种奇怪的行为(未定义行为的定义是任何事情都可能发生)。实际上,你运气并且内存仍然存在,处于您期望的状态。

示例:

 #include <iostream>

 struct A {
   A(): p(0) {}
   ~A() { if (p) { std::cout << *p << "\n"; } }
   int* p;
 };

 int bar0();
 void bar1(int i);

 int main() {
   A a;
   {
     int x = 4; a.p = &x;
   }
   {
     int y = bar0(); bar1(y);
   }
 }

 int bar0() { return 7; }
 void bar1(int i) { std::cout << i << "\n"; }

在这里,编译器可以选择为x重用y的空间,或者只是做任何想做的事情,因此你实际上是在打印垃圾。

这是gcc 4.3.4(和4.5.1)输出(由ideone提供):

7
4

意味着空间不会与那些空间重复使用......