static_cast and temporary creation (final edition)

2019-05-07 13:13发布

问题:

Prerequisities: To understand this question, please, read the following question and its answer at first: Cast auto_ptr<Base> to auto_ptr<Derived>

At Cast auto_ptr<Base> to auto_ptr<Derived> Steve answered that "Your static_cast would copy the auto_ptr to a temporary, and so aS would be reset and the resource would be destroyed when the temporary is (at the end of the statement)."

I'm interested in the process of temporary creation while static_cast is called. I would like to have the code that I can trace in order to see this effect. I cannot use static_cast<auto_ptr<Circle>> ... because it cannot be compiled, so I need to write some simulation class instead of auto_ptr and watch the process of temporary creation.

I also understand that temporary creation is closely connected with copy constructor call. auto_ptr's ownership loosing is simulated with copy assignment that set the _radius field of source to negative value (I need the simple logical model of auto_ptr).

So, I suggest the following Circle class:

#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;
}

Ok. Here we can see that "ownership transferring" is taking place in c2 = c3. BUT I cannot achieve temporary creation in static_cast.

The question is: how to make a small simulation of temporary object creation while static_cast?

I believe Steve that temporary object is created while casting. The only thing I want is to write an example that shows temporary creation. This target has academic reasons.

Can someone clarify how to achieve the effect described in Steve's answer that he posted at the referred topic?

回答1:

In your previous question, auto_ptr is the class that has ownership, and resets the source's pointer to null when it is copied.

Now, Circle is a class that simulates ownership, by resetting its radius to -1 when it is copied. So it's like an auto_ptr in that way, but not in any other way.

So, to observe loss of simulated ownership you need to copy a Circle, which is what you do with copy assignment in the line c2 = c3. Casting a Circle* doesn't copy the object, just the pointer, but casting a Circle does copy the object:

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

Output is -1.

Or if you specifically want to see it with a cast to a derived class:

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';
}


回答2:

Ok. Here we can see that "ownership transferring" is taking place in c2 = c3. BUT I cannot achieve temporary creation in static_cast.

static_cast<Circle> (c2); 

will "steal" from c2.



回答3:

You're fine with the auto_ptr. As Steve's answer explains, the language is smart enough to do this with ordinary pointers. Casting a pointer between base and derived classes can require changing the value of the pointer, and a static_cast will do that when needed.



回答4:

The simplest I could think of is this (if you change the example in your original question) :

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

This :

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

creates a temporary of type auto_ptr< Circle >, which destructs the object of type auto_ptr< Shape > at the end of the scope.

Here is an example (I hope it is clear enough) :

#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;
}