static_cast和临时创建(最终版)

时间:2011-12-20 20:08:42

标签: c++ casting static-cast temporary-objects

Prerequisities: 要理解这个问题,请首先阅读以下问题及其答案: Cast auto_ptr<Base> to auto_ptr<Derived>

目前 Cast auto_ptr<Base> to auto_ptr<Derived> Steve回答说“你的static_cast会将auto_ptr复制到临时版本,因此aS会被重置,当临时版本(在语句末尾)时资源将被销毁。”

我在调用static_cast时对临时创建过程感兴趣。 我想拥有我可以追踪的代码,以便看到这种效果。 我不能使用static_cast<auto_ptr<Circle>> ...因为它无法编译,所以我需要编写一些模拟类而不是auto_ptr并观察临时创建的过程。

我也理解临时创建与复制构造函数调用密切相关。 auto_ptr的所有权丢失是通过复制分配来模拟的,该分配将源_radius字段设置为负值(我需要auto_ptr的简单逻辑模型)。

所以,我建议使用以下Circle类:

#include <iostream>

class Shape {};

class Circle: public Shape {
  double _radius;
public:
  explicit Circle(double radius = .5): _radius(radius) {}
  Circle &operator =(Circle &circle) {
    _radius = circle._radius;
    circle._radius = -1.;
    return *this;
  }
  Circle(Circle &circle) { *this = circle; }
  double GetRadius() { return _radius; }
};

int wmain() {
  using namespace std;

  Circle c1(100), c2(200), c3(300);
  c2 = c3;

  Shape *s1, s2;
  s1 = &c1;
  wcout << static_cast<Circle *>(s1)->GetRadius() << endl;

  return 0;
}

确定。在这里,我们可以看到“所有权转移”正在c2 = c3中发生。 但我无法在static_cast中实现临时创作。

问题是:如何在static_cast时创建临时对象的小模拟?

我相信Steve在施法时会创建临时对象。我唯一想要的是编写一个显示临时创建的示例。这个目标有学术上的原因。

有人可以澄清如何达到他在推荐主题上发表的史蒂夫答案所描述的效果吗?

4 个答案:

答案 0 :(得分:3)

在上一个问题中,auto_ptr是拥有所有权的类,并在复制时将源的指针重置为null。

现在,Circle是一个模拟所有权的类,通过在复制时将其半径重置为-1。所以它就像auto_ptr那样,但不是以任何其他方式。

因此,要观察模拟所有权的丢失,您需要复制Circle,这就是您在行c2 = c3中使用复制分配所做的工作。转换Circle*不会复制对象,只会复制指针,但是转换Circle会复制对象:

int main() {
    Circle c1(100);
    static_cast<Circle>(c1);
    std::cout << c1.GetRadius() << '\n';
}

输出为-1。

或者,如果您特别希望通过强制转换为派生类来查看它:

struct SpecialCircle: Circle {
    SpecialCircle(Circle &circle) : Circle(circle) {}
    explicit SpecialCircle(double radius = .5): Circle(radius) {}
};

int main() {
    SpecialCircle s1(100);
    Circle &c1 = s1;
    static_cast<SpecialCircle>(c1);
    std::cout << c1.GetRadius() << '\n';
}

答案 1 :(得分:1)

  

确定。在这里,我们可以看到“所有权转移”发生在c2 = c3。但我无法在static_cast中实现临时创作。

static_cast<Circle> (c2); 

将从c2“窃取”。

答案 2 :(得分:0)

你对auto_ptr没问题。正如Steve's answer所解释的那样,语言足够聪明,可以用普通指针来完成。在基类和派生类之间转换指针可能需要更改指针的值,static_cast将在需要时执行此操作。

答案 3 :(得分:0)

我能想到的最简单的是(如果你改变your original question中的例子):

wcout << aS->GetName() << L'\t' << static_cast<auto_ptr<Circle>>(aS.get())->GetRadius() << endl;

这:

static_cast<auto_ptr<Circle>>(aS.get())

创建一个auto_ptr< Circle >类型的临时表,它会在范围的末尾销毁类型为auto_ptr< Shape >的对象。

这是一个例子(我希望它足够清楚):

#include <iostream>
#include <memory>

struct B
{
    ~B()
    {
        std::cout<<"~B"<<std::endl;
    }
    void foo()
    {
        std::cout<<"foo"<<std::endl;
    }
};
struct A : B
{
    ~A()
    {
        std::cout<<"~A"<<std::endl;
    }
    void bar()
    {
        std::cout<<"boom"<<std::endl;
    }
};

int main() {
    std::auto_ptr< A > a( new A );
    {
        std::auto_ptr< B > b( a.get() );
        b->foo();
    }

    std::cout<<"prepare for the crash"<<std::endl;
}