简体   繁体   中英

Closing a connection in a destructor in C++

I was thinking about a C++ class that manages my TCP connections (on Linux). Upon destruction the connection should be closed similar to this:

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

The problem is that when putting an object of this class into eg a vector the connection will also be closed like this even though I would still like to use the connection. How can I solve this? Is this a bad idea in general?

What you want to implement is a design pattern called RAII, so once your TCPConnection is instatiated it aquires resources, once it is destroyed it releases resources. If it was destroyed then it means that programmer intention was to stop using those resources. If you need to still use them, then you must prolong lifetime of your object. You can use typedef std::shared_ptr<TCPConnection> TCPConnectionPtr , then you can put your TCPConnectionPtr instances in many places and your connection will be closed only once all those instances are destroyed.


example code ( 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();
}

Store the TCPConnection as a pointer in a std::vector<TCPConnection*> rather than an an instance. Then when you need to tidy up you can just delete the pointer.

Alternatively, if you've got access to std::shared_ptr you can store that in the vector instead, and when nothing else is referencing each connection then the connection will be deleted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM