Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > приоритет перегруженных операторов


Автор: nerdy_weirdie 29.3.2011, 04:15
Столкнулся с очень странным поведением компилятора VS2005.
Вместо того чтобы использовать подходящий оператор присваивания, он вызывает оператор приведения к другому типу, и затем вызывает перегруженный оператор присваивания.
Почему он так делает, и как этого избегать. Решение всегда явно задавать тип при вызове оператора присваивания не подходит потому что слишком не надежное - кода много и где-нибудь обязательно да забудется. Надо чтобы компилятор сам выбирал нужный оператор.
Код

class CSock
{ ...
    operator SOCKET ();
    CSock& operator  = (SOCKET p_sockFrom);
    CSock& operator  = (CSock& p_sockFrom); ...
}
CSock FindSocket(){...}
void MainProc()
{
 CSock sock = 0;
 sock = FindSocket(); // здесь происходит странное
}

Казалось бы, будет вызван оператор CSock& operator  = (CSock& p_sockFrom); и всё будет работать как надо, но почему-то в этой строке возвращенный объект сначала преобразуется к типу SOCKET при помощи operator SOCKET (); и затем для присвоения вызывается CSock& operator  = (SOCKET p_sockFrom);. В итоге логика учета референсов не работает. Как научить его ходить в лоток?

Автор: borisbn 29.3.2011, 06:46
Не решение, а так... костылёк...
А что если в описании класса поднять "правильный" оператор присваивания вверх, перед "неправильными"?

Автор: Earnest 29.3.2011, 07:26
Лучше убрать нафик оператор приведения. Это вообще штука опасная, чревата всякими непредсказуемыми поведениями, особенно для активно развивающегося кода.
Лучше замени его явной функцией. И, скорее всего, это константная функция должна быть.
Кроме того, хороший тон требует, чтобы оператор присваивания получал константные ссылку, а не копию и уж тем более не просто ссылку.

Автор: borisbn 29.3.2011, 08:28
Цитата(Earnest @  29.3.2011,  07:26 Найти цитируемый пост)
Кроме того, хороший тон требует, чтобы оператор присваивания получал константные ссылку, а не копию и уж тем более не просто ссылку.

судя по всему, не только хороший тон, но и студия smile проверил. заменил на
CSock& operator  = ( const CSock& p_sockFrom);
стал вызываться этот конструктор

Автор: bsa 29.3.2011, 10:32
nerdy_weirdie, функция FindSocket() возвращает так называемое rvalue, т.е. временный объект. По стандарту С++, нельзя такие объекты передавать в качестве параметров функциям, принимающим объекты по неконстантной ссылке. Так как у тебя есть оператор преобразования (что вообще считается дурным тоном, так как может вызывать подобные проблемы) и оператор присваивания принимающий SOCKET, то компилятор их и использует.

По хорошему, достаточно сделать конструктор от (const SOCKET&), чтобы при присваивании объекта типа SOCKET вызвался он, а затем operator=(const CSock&) для полученного объекта:
Код
class CSock
{
    //...
    CSock(); //делает зануление, вместо sock=0
    //CSock(const CSock &sockFrom); //конструктор копирования, ОБЯЗАТЕЛЬНО нужен, если есть выделение ресурсов
    //~CSock(); //деструктор, ОБЯЗАТЕЛЬНО нужен, если есть выделение ресурсов в конструкторах
    CSock(const SOCKET &sockFrom);
    CSock& operator=(const CSock &sockFrom) {
        CSock(sockFrom).swap(*this);
        return *this;
    }
    void swap(CSock &sock);   //сильно упрощает жизнь
    SOCKET toSOCKET() const; //не вызывает неоднозначностей, в отличие от оператора приведения типа
};
CSock FindSocket(){...}
void MainProc()
{
 CSock sock;
 sock = FindSocket();
}

Автор: nerdy_weirdie 29.3.2011, 17:25
Спасибо, с константной ссылкой работает. Но всё равно такое поведение мне кажется неадекватным.

Автор: borisbn 29.3.2011, 17:52
Цитата(nerdy_weirdie @  29.3.2011,  17:25 Найти цитируемый пост)
Но всё равно такое поведение мне кажется неадекватным.


Цитата(bsa @  29.3.2011,  10:32 Найти цитируемый пост)
функция FindSocket() возвращает так называемое rvalue, т.е. временный объект. По стандарту С++, нельзя такие объекты передавать в качестве параметров функциям, принимающим объекты по неконстантной ссылке.


я правильно понял, что поведение компилятора по стандарту кажется неадекватным smile
 smile 
Бедная M$. Делает не по стандарту (кстати, довольно часто) - ругают. Делают по стандарту - получите, распишитесь smile

оффтопиковый  smile 
а что ты хотел от класса СНосок ?
 smile 

Автор: kemiisto 29.3.2011, 17:59
Цитата(borisbn @  29.3.2011,  15:52 Найти цитируемый пост)
я правильно понял, что поведение компилятора по стандарту кажется неадекватным

По-моему, у ТС сомнения в адыкватности стандарта. То есть в адыкватности языка.

Сомнения правильные. smile Раунд 100500! Гонг! Поехали!

Автор: borisbn 29.3.2011, 21:27
Цитата(kemiisto @  29.3.2011,  17:59 Найти цитируемый пост)
 Раунд 100500! Гонг! Поехали!

поехали.
Апперкот - компилятор Си++ есть на все известные платформы (кроме разве что андроида)
1 : 0

Автор: kemiisto 29.3.2011, 21:30
Цитата(borisbn @  29.3.2011,  19:27 Найти цитируемый пост)
Апперкот - компилятор Си++ есть на все известные платформы (кроме разве что андроида)
1 : 0 

Казалось бы, и причём тут адыкватность? smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)