2015-09-09 3 views
0

Я написал минимальный пример для проверки некоторого поведения. Я попытался получить std::dynamic_pointer_cast сбой, но столкнулся с неожиданным поведением.std :: dynamic_pointer_cast успешный вызов не инициализированного класса

Вот минимальный пример, который я использовал:

//virtual_ipsum.h 
class virtual_ipsum 
{ 
public: 
    virtual_ipsum() { } 
    virtual ~virtual_ipsum() { } 
}; 
//derived_lorem.h 
#include "virtual_ipsum.h" 
#include <iostream> 
#define UUID_DERIVED_LOREM_RANDOM 2 //rolled it myself 
class derived_lorem : 
    public virtual_ipsum 
{ 
public: 
    derived_lorem(){ } 
    ~derived_lorem(){ } 
    void o(){ std::cout << "lorem" << std::endl; }; 
}; 
//derived_adipiscing.h 
#include "virtual_ipsum.h" 
#include <iostream> 
#define UUID_DERIVED_ADIPISCING_RANDOM 24 //rolled it myself 
class derived_adipiscing : 
    public virtual_ipsum 
{ 
public: 
    derived_adipiscing(){ } 
    ~derived_adipiscing(){ } 
    void elit(){ std::cout << "donec" << std::endl; }; 
}; 
//server.h 
#include <memory> 
#include "virtual_ipsum.h" 
//note that the header of the server can not contain the derived classes. 

class server 
{ 
public: 
    server() {} 
    ~server() {} 
    std::shared_ptr<virtual_ipsum> getDerivedClassByUUID(int UUID); 
}; 
//server.cpp 
#include "server.h" 
#include "derived_lorem.h" 
std::shared_ptr<virtual_ipsum> server::getDerivedClassByUUID(int UUID) 
{ 
    // after careful examination of the UUID the 
    // server will send the correct derived class 
    return std::make_shared<derived_lorem>(); 
} 
//client.h 
#include <memory> 
#include "server.h" 
class client 
{ 
private: 
    std::shared_ptr<server> s; 
public: 
    client(std::shared_ptr<server> s) : s(s){} 
    ~client(){} 
    void dolor(); 
    void consectetur(); 
}; 
//client.cpp 
#include "client.h" 
#include "derived_lorem.h" 
#include "derived_adipiscing.h" 
#include <memory> 
void client::dolor() 
{ 
    std::shared_ptr<virtual_ipsum> sit = s->getDerivedClassByUUID(UUID_DERIVED_LOREM_RANDOM); 
    std::shared_ptr<derived_lorem> amet = std::dynamic_pointer_cast<derived_lorem>(sit); 
    amet->o(); 
} 
void client::consectetur() 
{ 
    std::shared_ptr<virtual_ipsum> felis = s->getDerivedClassByUUID(UUID_DERIVED_LOREM_RANDOM); 
    //everything should crash and burn 
    std::shared_ptr<derived_adipiscing> mauris = std::dynamic_pointer_cast<derived_adipiscing>(felis); 
    mauris->elit(); 
} 
//main.cpp 
#include <memory> 
#include "server.h" 
#include "client.h" 

void main() 
{ 
    std::shared_ptr<server> s = std::make_shared<server>(); 
    std::shared_ptr<client> c = std::make_shared<client>(s); 
    c->dolor(); 
    c->consectetur(); 
} 

Выход на моей машине: output of minimal example

Вызов c->consectetur(); должен терпеть неудачу, так как сервер возвратил неправильно производный класс. Вместо этого бросок не только успешный, но и завершенный, как если бы он был правильным классом.

Как я могу обнаружить эту проблему на стороне клиента во время кастинга?

+0

, если '' amet' является nullptr' (из-за отказа динамического броска), то это UB. вы можете проверить, не является ли он непустым –

+0

А, я добавил чек для этого, и теперь код обнаруживает его. Благодарю. Является ли выполнение c-> consectetur() неопределенным, и мне просто повезло или он хорошо определен, так как я ввел его в заголовок? – Johannes

+0

Это неопределенное поведение –

ответ

1

Как показывают приведенные выше комментарии указывают:

  • вызова mauris->elit(); не определен.
  • std :: shared_ptr может быть просто пустым.
  • пустота главный делает людей несчастными

Изменение реализации клиента к следующему решает эту проблему.

#include "client.h" 
#include "derived_lorem.h" 
#include "derived_adipiscing.h" 
#include <memory> 

void client::dolor() 

{ 
    std::shared_ptr<virtual_ipsum> sit = s->getDerivedClassByUUID(UUID_DERIVED_LOREM_RANDOM); 
    std::shared_ptr<derived_lorem> amet = std::dynamic_pointer_cast<derived_lorem>(sit); 
    if (amet) 
    { 
     amet->o(); 
    } 
    else 
    { 
     std::cout << "amet is null" << std::endl; 
    } 

} 

void client::consectetur() 
{ 
    std::shared_ptr<virtual_ipsum> felis = s->getDerivedClassByUUID(UUID_DERIVED_LOREM_RANDOM); 
    //everything should crash and burn 
    std::shared_ptr<derived_adipiscing> mauris = std::dynamic_pointer_cast<derived_adipiscing>(felis); 

    if (mauris) 
    { 
     mauris->elit(); 
    } 
    else 
    { 
     std::cout << "mauris is null" << std::endl; 
    } 
} 

новый выход: enter image description here

+0

* "вызов' mauris-> elit(); 'undefined." * Только когда 'mauris' может быть' nullptr' –

Смежные вопросы