2014-02-02 2 views
2

Я думал о классе C++, который управляет моими TCP-соединениями (в Linux). После разрушения соединение должно быть закрыто примерно так:Закрытие соединения в деструкторе в C++

TCPConnection::~TCPConnection() 
{ 
    close(_socket); 
} 

Проблема заключается в том, что при вводе объекта этого класса в, например, вектор, соединение также будет закрыто, хотя я все равно хотел бы использовать соединение. Как я могу это решить? Это вообще плохая идея?

+1

Либо сделать ваш класс двигаться только (не копируемой), или использовать его с помощью указателей. – qwm

+1

Это хорошая идея, ее называют RAII. – Paranaix

+0

+1 за попытку RAIfy вашего кода/практики на C++. RAII упрощает и упрощает управление ресурсами. Как вы заметили, RAII работает, связывая ресурс ресурса с временем жизни/областью дескриптора, который его управляет. Поэтому, когда объем дескриптора заканчивается, ресурс освобождается. Если вам нужно разделить ресурс между разными точками (то есть ** поделиться собственностью ресурса **), вы могли бы (должны) использовать 'std :: shared_ptr', который предназначен для безопасного доступа (без утечки)) владение ресурсом. – Manu343726

ответ

6

То, что вы хотите реализовать, представляет собой шаблон проектирования, называемый RAII, поэтому, когда ваш TCPConnection установлен, он приобретает ресурсы, после его уничтожения он освобождает ресурсы. Если он был уничтожен, это означает, что намерение программиста состояло в том, чтобы прекратить использование этих ресурсов. Если вам нужно их использовать, то вы должны продлить срок службы своего объекта. Вы можете использовать typedef std::shared_ptr<TCPConnection> TCPConnectionPtr, тогда вы можете поместить свои экземпляры TCPConnectionPtr во многие места, и ваше соединение будет закрыто только после уничтожения всех этих экземпляров.


пример кода (http://coliru.stacked-crooked.com/a/581a856ee32890d2):

#include <iostream> 
#include <vector> 
#include <memory> 

class TCPConnection { 
    int inst; 
    static int inst_count; 
public: 
    TCPConnection() { inst=inst_count++; std::cout << "TCPConnection created: " << inst << std::endl; } 
    ~TCPConnection() { std::cout << "TCPConnection destroyed:" << inst << std::endl; } 
}; 
int TCPConnection::inst_count; 

// version if If c++11 is available, can be also implemented with boost::shared_ptr 
// Removing individual TCPConnection from vector will also decrement its shared_ptr 
// usage count and if it is zero then will destroy also such connections. 
typedef std::shared_ptr<TCPConnection> TCPConnectionPtr; 
typedef std::vector<TCPConnectionPtr> TCPConnectionPtrVec; 

void fun1() { 
    TCPConnectionPtrVec vec; 
    vec.push_back(TCPConnectionPtr(new TCPConnection())); 
} 

// version for pre c++11 compiler, but I would recomend using boost::shared_ptr 
// Class TCPConnectionsVecWrapper is a helper to make sure connections are safely freed. 
class TCPConnectionsVecWrapper { 
    // No copying allowed 
    TCPConnectionsVecWrapper(const TCPConnectionsVecWrapper&); 
    TCPConnectionsVecWrapper& operator=(const TCPConnectionsVecWrapper&);  

    typedef std::vector<TCPConnection*> TCPConnectionPtrsVec;  
    TCPConnectionPtrsVec vec;  
public: 
    TCPConnectionsVecWrapper() {} 
    ~TCPConnectionsVecWrapper() { 
     for (TCPConnectionPtrsVec::const_iterator itr = vec.begin(); itr != vec.end(); ++itr) delete *itr; 
    } 

    TCPConnection* createConnection() { 
     vec.push_back(new TCPConnection()); 
     return vec.back(); 
    } 

    void remove(int index) { 
     delete vec[index]; 
     vec.erase(vec.begin() + index); 
    } 

    TCPConnection* get(int index) { return vec[index]; } 
    const TCPConnection* get(int index) const { return vec[index]; } 

    std::size_t size() const { return vec.size(); }   
}; 

void fun2() { 
    // All TCPConnection will get deleted once tcpConnectionsWrapper is out of scope 
    TCPConnectionsVecWrapper conns; 

    TCPConnection* con1 = conns.createConnection(); 
    (void)con1; // unused 
    TCPConnection* con2 = conns.createConnection(); 
    (void)con2; // unused 

    for (size_t i = 0; i < conns.size(); ++i) { 
    TCPConnection* con = conns.get(i); 
    (void)con; // unused 
    } 
    conns.remove(0); 
} 

int main(int argc, char** argv){ 
    fun1(); 
    fun2(); 
} 
+0

Также красивый стиль 'struct Foo {typedef std :: shared_ptr Ptr; }; ' – Paranaix

+0

Это хороший ответ. Но подумайте о том, чтобы включить пример кода, чтобы сделать его более понятным для OP. – Manu343726

+0

Я добавил пример кода, надеюсь, он будет полезен OP – marcinj

0

Храните TCPConnection в качестве указателя в std::vector<TCPConnection*>, а не в экземпляре. Затем, когда вам нужно привести в порядок, вы можете просто удалить указатель.

В качестве альтернативы, если у вас есть доступ к std::shared_ptr, вы можете сохранить это в vector вместо этого, и когда ни одно другое не ссылается на каждое соединение, соединение будет удалено.

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