Closing a connection in a destructor in C++

c++, networking

Solution

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

Problem

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 e.g. 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?

Original source