2015-02-27 8 views
2

У меня есть класс под названием Camera, который открывает в конструкторе камеру с v4l2_open и т. Д. Деструктор выполняет некоторую очистку и закрывает дескриптор файла с помощью v4l2_close.Должен ли я использовать указатель на объект или объект, когда объект представляет собой компонент оборудования?

Когда происходит сбой камеры, что я делаю, чтобы удалить объект, а затем создать новый:

Camera *camera = new Camera(); 
(...) 
if (crash) { 
    delete camera; 
    camera = new Camera(); 
} 

Это один из правильного использования новых/удаления в C++?

+3

Возможный дубликат [Почему я должен использовать указатель, а не сам объект?] (Http://stackoverflow.com/questions/22146094/why-should-i-use-a-pointer-rather-than-the -объект-сам) –

+2

Предпочитаете использовать объект. Если вы должны выделить динамически, предпочитайте использовать интеллектуальный указатель на объект в куче. –

+2

Зачем людям подобные вопросы? Иногда я не понимаю, ребята. –

ответ

6

Нет, использование new и delete здесь не является обязательным. Если ваша камера «плохая», и вы хотите избавиться от нее в пользу новой, просто назначьте новую.

const std::string device {"/dev/cameras/front"}; // whatever 
Camera camera {device}; 
// do something... 
if (camera.bad()) 
    camera = Camera {device}; // replace by a new one 

Вы, вероятно, хотите overload the assignment operator вашего Camera класса для этой работы. Поскольку класс Camera является ресурсоемким, его нельзя копировать, а перемещать. Я не знаю, как вы разговариваете с аппаратными средствами, поэтому я сделал следующий пример немного, но он должен дать вам правильную идею о том, как реализовать свой тип.

extern "C" 
{ 
    // I have made these up... 
    int camera_open(const char *); 
    int camera_close(int); 
} 

class Camera 
{ 

private: 

    // Initially set to arbitrary nonsensical values. 
    std::string device_ {}; 
    int fd_ {-1}; 

public: 

    Camera() noexcept 
    { 
    } 

    Camera(const std::string& device) : device_ {device} 
    { 
    this->open(); 
    } 

    ~Camera() noexcept 
    { 
    try 
     { 
     this->close(); 
     } 
    catch (const std::exception& e) 
     { 
     // Cannot throw from a destructor... 
     std::cerr << e.what() << std::endl; 
     } 
    } 

    Camera(const Camera&) = delete; // not copy-constructible 

    Camera(Camera&& other) : Camera {} 
    { 
    swap(*this, other); 
    } 

    Camera& operator=(const Camera&) = delete; // not copy-assignable 

    Camera& 
    operator=(Camera&& other) noexcept 
    { 
    Camera tmp {}; 
    swap(*this, tmp); 
    swap(*this, other); 
    return *this; 
    } 

    friend void 
    swap(Camera& first, Camera& second) noexcept 
    { 
    using std::swap; 
    swap(first.device_, second.device_); 
    swap(first.fd_, second.fd_); 
    } 

    void 
    reopen() 
    { 
    this->close(); 
    this->open(); 
    } 

    void 
    open(const std::string& device = "") 
    { 
    if (this->fd_ >= 0) 
     throw std::runtime_error {"camera already open"}; 
    if (!device.empty()) 
     this->device_ = device; 
    if (this->device_.empty()) 
     throw std::runtime_error {"no associated device"}; 
    this->fd_ = camera_open(this->device_.c_str()); 
    if (this->fd_ < 0) 
     throw std::runtime_error {"cannot open camera"}; 
    } 

    void 
    close() 
    { 
    if (this->fd_ >= 0) 
     { 
     if (camera_close(this->fd_) != 0) 
      throw std::runtime_error {"cannot close camera"}; 
     this->fd_ = -1; 
     } 
    } 
}; 

Но вы уверены, что это действительно хорошее дизайнерское решение в первую очередь? Может быть, камера может просто «перезагрузить» себя, когда это необходимо, и вообще не беспокоить пользователя этой деталью реализации?

+2

Я думаю, что он зависит от необходимой внутренней функциональности класса, может ли он просто назначить новый объект. Если при удалении камеры необходимо очистить и освободить ресурсы, ему необходимо вызвать 'camera.cleanup()' или использовать указатели и вызвать 'delete camera', чтобы деструктор очистился. В любом случае, как вы уже упоминали, 'reload()' будет намного лучше. –

+3

@TobiasKnauss Я не согласен с этим. Ответственность за сам тип заключается в освобождении любых ресурсов, которыми он владеет при назначении нового значения. В этом весь смысл RAII и гораздо безопаснее, чем необходимость запоминать вручную функцию очистки на всех путях выполнения. Рассмотрим, например, 'std :: string'.Если вы присвоите ему новое значение, то ответственность за освобождение старого буфера будет зависеть от строки, если она больше не нужна. Добавленный код демонстрирует, как это можно реализовать. – 5gon12eder

+0

Хорошо, позвольте мне попытаться понять альтернативы. –