2017-02-16 3 views
0

Позвольте мне начать с утверждения, что я использую компилятор GNU C++, который НЕ поддерживает конструкторы перемещения. Он поддерживает только стандарт 98.RAII, Berkeley Sockets и STL Containers

Учитывая, что я хочу написать класс C++, который объединяет сокеты стиля Berkeley простым способом, который следует за RAII. Вот очень простой класс:

class SimpleSocket 
{ 
    int m_sockfd; 
public: 
    SimpleSocket() 
    { 
    m_sockfd = socket(AF_INET, ...); 
    } 
    SimpleSocket(const SimpleSocket& other) 
    { 
    m_sockfd = other.m_sockfd; 
    } 
    ~SimpleSocket() 
    { 
    closeSocket(); 
    } 
    void closeSocket() 
    { 
    if(m_sockfd != -1) 
    { 
     close(m_sockfd); 
     m_sockfd = -1; 
    } 
    } 
}; 

Скажем, я хочу, чтобы создать целую кучу их в STL C++ вектор, как так.

vector<SimpleSocket> vec_of_sockets; 
for(int i = 0 ; i < 10 ; ++i) 
{ 
    SimpleSocket new_sock; 
    vec_of_sockets.push_back(new_sock); 
} 

То, что я обнаружил, что вектор использует конструктор копирования для перемещения объектов вокруг, а затем разрушающие старые гнезда. У этого есть неудачный побочный эффект вызова closeSocket(), который закрывает мой файловый дескриптор.

Я хочу следовать за RAII и закрывать дескриптор файла при вызове деструктора объекта, но он делает его там, где я не могу использовать его внутри контейнеров STL C++. Я знаю, что могу обновить свой компилятор и реализовать конструктор перемещения, который бы устранил проблему, но я работаю в компании, которая не верит в использование чего-либо современного. (Я действительно разочарован им, но ничего не могу поделать.)

+0

Попробуйте изменить конструктор копирования и удалите 'const', а затем установите' other.m_sockfd' в -1 после того, как вы его скопировали. Вероятно, вы также хотите подумать о 'operator ='. –

+0

@RichardCritten у вас не может быть copy-constructor без ссылки const. ваше предложение бессмысленно –

+0

@DavidHaim Да, вы можете: _ «Конструктор копирования класса T является конструктором без шаблона, первым параметром которого является __T & __, const T &, volatile T & или const volatile T & _ _ (мой полужирный): http : //en.cppreference.com/w/cpp/language/copy_constructor Он не будет копировать временные объекты - вот почему я сказал «Try» в своем сообщении. –

ответ

1

Если бы вы могли использовать Smart Pointers Boost library, хранить класс внутри shared_ptr как в:

std::vector<boost::shared_ptr<SimpleSocket>> 
2

И Linux, и Windows, осуществлять подсчет ссылок на уровне ядра/winsock2. вы могли бы использовать указатель подсчета ссылок в своей программе пользовательского режима, но это потеряло бы больше памяти, чем вы думаете. вы можете поднять ссылку, подсчитав, что ОС уже делает за кулисами. вот пример реализации для Linux:

SimpleSocket(const SimpleSocket& other) 
    { 
    m_sockfd = dup(other.m_sockfd); 
    } 

Операционная система будет увеличивать счетчик ссылок указанного сокета и возвращает новый дескриптор, в котором вы можете использовать. что когда вы «копируете» сокет таким образом, оба сокета будут ссылаться на один и тот же базовый сокет, даже если дескрипторы разные.

+1

Вам необходимо использовать [WSADuplicateSocket] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms741565 (v = vs.85) .aspx) в Windows. Я бы также реализовал перегруженный оператор присваивания для класса. – selbie

+0

Я не знаю почему, но я думал, что это не сработает для того, что я делаю. Я думал, что это проблема, когда каждый файловый дескриптор ссылается на один и тот же, поэтому, если я закрою один, он закроет другой. –

+0

@selbie Что касается перегруженного оператора присваивания, вы бы отказались от того, чтобы его не назначали (выкидывали исключение), или вы бы дублировали сокет, как в конструкторе копирования? –