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


Автор: _hunter 7.4.2005, 22:10
Добрый день.

Можно ли сделать/объявить действительно константную ссылку?

т.е. я сейчас делаю так:

const std::vector<int>& SomeFunction();
и, соответственно:
const std::vector<int>& data = SomeFunction();
но компилятор пропускает data.clear();

этого можно как-то избежать?

Заранее благодарю за ответ.

Автор: Fire-Plug 7.4.2005, 22:36
Спецификатор const в обьявлении обьекта(переменной, ссылки, указателя) указывает компилятору, что изменять состояние обьекта нельзя (т.е. его следует рассматривать как read-only)
Если вектор действительно нужно очистить, ссылку следует обьявить как
Код

std::vector<int>& data= const_cast <std::vector<int>&>(SomeFunction());

Автор: Fire-Plug 7.4.2005, 23:56
Цитата(_hunter @ 7.4.2005, 22:10)
но компилятор пропускает data.clear();


О, блин, сорри - показалось "компилятор НЕ пропускает...."
Надо думать...

Автор: chipset 8.4.2005, 00:59
А если ссылку на константный обьект попробовать?

Автор: Fire-Plug 8.4.2005, 02:11
Каким компилятором ты пользуешься?
VC6 и выше вызов clear() для констатной ссылки на объект не пропускает, сообщая при этом, что не может конвертнуть this-указатель констатного объекта в неконстантный
Код

vector<int> vInt; // как-то инициализирован
 . . . 
const vector<int>& сrVect= vInt;
сrVect.clear();
=====
error C2662: 'clear' : cannot convert 'this' pointer from 'const class std::vector<int,class std::allocator<int> >'
to 'class std::vector<int,class std::allocator<int> > &'

Автор: srd 8.4.2005, 02:14
Ты где то ошибся.
Пытаюсь скомпилировать следующий код:
Код

#include <vector>

std::vector<int> vector;

const std::vector<int> &SomeFunction(void)
{
    return vector;
}


int main(void)
{
    const std::vector<int> &v = SomeFunction();
    v.clear();
    return 0;
}

Получаю ошибку:
Цитата

d:\documents\Visual Studio Projects\tst\main.cpp(14): error C2662: 'std::vector<_Ty>::clear' : cannot convert 'this' pointer from 'const std::vector<_Ty>' to 'std::vector<_Ty> &'
        with
        [
            _Ty=int
        ]
        and
        [
            _Ty=int
        ]
        and
        [
            _Ty=int
        ]

Так что константная ссылка действительно константна.

Автор: DENNN 8.4.2005, 09:28
Цитата(Fire @ 8.4.2005, 02:11)
VC6 и выше вызов clear() для констатной ссылки на объект не пропускает,

ИМХО, вопрос реализации и версии STL. На других платформах может быть иначе.

Автор: chipset 8.4.2005, 09:43
_hunter, а ты случаем Borland'овский компилер юзаешь? Я слышал, у него бывают заскоки по фазе...
Вообще я согласен с DENNN'ом smile

Автор: DENNN 8.4.2005, 10:47
Цитата(srd @ 8.4.2005, 02:14)
Так что константная ссылка действительно константна.

ССылка то константна, но вот получить по этой ссылке доступ к методам класса ты можешь - > нет никакой гарантии что вызванный метод не изменит свои внутренние данные.

Автор: chipset 8.4.2005, 10:54
Цитата(DENNN @ 8.4.2005, 00:47)
ССылка то константна, но вот получить по этой ссылке доступ к методам класса ты можешь - > нет никакой гарантии что вызванный метод не изменит свои внутренние данные.

Если я не ошибаюсь, методу константного обьекта класса передается константный this и компилер плюется при попытке изменить данные.

Автор: srd 8.4.2005, 10:59
Цитата(DENNN @ 8.4.2005, 17:47)
ССылка то константна, но вот получить по этой ссылке доступ к методам класса ты можешь - > нет никакой гарантии что вызванный метод не изменит свои внутренние данные.

Для константного объекта данные-члены доступны только на чтение, а из функций-членов доступны только опять-таки константные (т.е. определённые с модификатором const) и статические. Из константных методов менять можно только статические поля и поля со спецификатором mutable, а из статических методов - только статические поля. Так-что гарантия есть.

Цитата(DENNN @ 8.4.2005, 16:28)
ИМХО, вопрос реализации и версии STL. На других платформах может быть иначе.

Не может. Если реализация STL соответствует стандарту, то в ней метод clear() вектора не имеет модификатора const, а значит этот метод не может быть вызван для константных объектов.

Автор: np9mi7 8.4.2005, 14:54
стандарт языка с++ (наверное любой номер) говорит о том, что
Код

const T& a;
, объект на который ссылается так объявленная ссылка нельзя изменить. Чето где то глючит smile

А зачем возвращать const ссылку если пользователь твоей функции её только смотрит? Может имеет смысл вернуть копию объекта? Или это экономия памяти?

Автор: chipset 8.4.2005, 15:01
Цитата(np9mi7 @ 8.4.2005, 04:54)
Чето где то глючит smile

Я ж и говорю, билдерь наверное..
Сейчас придет _Хантер и расскажет smile

Автор: _hunter 8.4.2005, 15:30
сорри что так поздно пришел...

действительно пишу под билдером ( если это его прикол -- обидно smile )

np9mi7, не столько памяти сколько времени ( у меня этих чтений -- туева хуча )

полный код ( чтобы не было вопросов ):

Код

#include <vector>
//---------------------------------------------------------------------------

class A
{
private:
    std::vector<int> _data;
public:
    const std::vector<int>& GetData();
};

const std::vector<int>& A::GetData()
{
    return _data;
}

WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    A a;

    const std::vector<int>& data = a.GetData();
    data.clear();

    return 0;
}
//---------------------------------------------------------------------------


и единственное, что мне на это говорит компилятор:
[C++ Warning] W8037 Non-const function _STL::vector<int,_STL::allocator<int> >::clear() called for const object
и все smile

Автор: chipset 8.4.2005, 15:35
Значит билдерь пропускает константные вызовы, из еррора превращая их в ворнинги.

Автор: _hunter 8.4.2005, 15:54
ясно... (и обидно smile)

Автор: np9mi7 8.4.2005, 16:39
ну, так не меняй его? и warnings не будет!
ну как вы не понимаете, Builder с++ это чтоб на форму кнопки кидать, на нем мего надежных приложений не пишут! там и vcl только для этого.... smile

Автор: _hunter 8.4.2005, 16:42
я и не меняю. и проблема не в наличии предупрежедения при попытке изменения, а в отсутствии ошибки.

Автор: chipset 8.4.2005, 16:51
Если хочешь - можешь попробовать обернуть вектор в враппер запрещающий использовать изменяющие функции, хотя это конечно жуткий гемморой..

Автор: np9mi7 8.4.2005, 16:59
Цитата
Если хочешь - можешь попробовать обернуть вектор в враппер запрещающий использовать изменяющие функции, хотя это конечно жуткий гемморой..
. Зачем? Он же говорит что ребят так делать плохо - WARNING, типа и все тут!

Или ты в комманде, ну так на уровне бумаги напиши (если руководитель) что так писать нельзя.

У меня есть такой документ: Стилистические соглашения, в которых я все такие вещи обговариваю, потом все члены комманды крепят напротив себя это липучкой и все... smile . Ну если компилятор не может, что тогда smile

Автор: chipset 8.4.2005, 17:00
А ещё есть такая фича как "warning as error".

Автор: _hunter 8.4.2005, 17:39
так это только у меня будет...

а если я из модуля отдаю вектор в твердой уверенности что с ним ничего не сделают. а он пустым оказывается... ( это, пока, все на уровне теорий, но всеравно неприятно... )

Автор: np9mi7 8.4.2005, 17:53
Ну, при определении интерфейса к классу вообще плохой стиль давать внутренность! Возвращай копию и все!

Автор: _hunter 8.4.2005, 18:02
да знаю, что плохой стиль, но тут уже проблема скорости появляется ( я выше писал ) smile

Автор: np9mi7 8.4.2005, 18:07
Давай считать.
Сколько примерно объектов в контейнере smile
Какие операции хочешь совершать smile
Подожди, какая проблема скорости? Че долго откопировать один контейнер в другой? Те беж нужно его только смотреть, тогда время будет тратиться только на копирование!!!
Количество операций с сылкой или копией не измениться! Нет разве? Или я чего не понимаю?

Автор: chipset 8.4.2005, 18:10
_hunter, хм, а с защищеными кучами или отображениями файла поиграть если?

Автор: _hunter 8.4.2005, 18:14
примерно 3600. да тех классов еще под сотню ( это пока все в планах -- тестирование ведется на 100 первых и 2-х вторых )
+ проблема в том, что к первым классам доступ случайным будет ( т.е. получить вначале все копии не получится )

Автор: chipset 8.4.2005, 18:16
Цитата(np9mi7 @ 8.4.2005, 08:07)

Количество операций с сылкой или копией не измениться! Нет разве? Или я чего не понимаю?

Когда он передаст ссылку - скопируется 32 бита, когда скопирует массив - скопируется дофига_всего.
Добавлено @ 18:17
_hunter, ну раз много классов - выделяй из кучи - ставь READ_ONLY.

Автор: _hunter 8.4.2005, 18:20
а что за защищенные кучи?
с файлами не получится -- нужно подумать... но, чувствую, структуру классов кардинально переделывать придется...

Автор: np9mi7 8.4.2005, 18:25
Цитата
Когда он передаст ссылку - скопируется 32 бита, когда скопирует массив - скопируется дофига_всего.

это понятно, но количество операций которые он совершит с константной ссылкой после передачи не чуть не больше чем с копией. Разница только на этапе копирования.

Цитата
проблема в том, что к первым классам доступ случайным будет ( т.е. получить вначале все копии не получится )
, немного не ясно какие классы первые какие вторые?

или ты хочешь сказать что тебе нужна ссылка на объект который должен меняться, а ты хочешь его постоянно смотреть по этой ссылке smile (что то типа Dymanic recordset)

Автор: chipset 8.4.2005, 18:27
С отображенными файлами вроде точно такое можно сделать..
Про кучи, только что глянул, что-то очень сомнительная HeapLock да и то от других процессов..
Будем дальше думать.

Автор: chipset 8.4.2005, 18:40
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/creating_named_shared_memory.asp показан пример использования отображения как разделяемой памяти.

Автор: Fire-Plug 10.4.2005, 08:37
Цитата(_hunter @ 8.4.2005, 17:39)
а если я из модуля отдаю вектор в твердой уверенности что с ним ничего не сделают. а он пустым оказывается... ( это, пока, все на уровне теорий, но всеравно неприятно... )

Нехорошо это, внутренние переменные нетривиального содержания из класса наружу отдавать. Это же не совсем аналогично ситуации вида: size_t someclass:size() const; А как же инкапсуляция?
Ежели какому-то классу-клиенту этот вектор нужен для принципиальных целей, то это должен быть его атрибут. И он будет передавать его по ссылке методу класса-хэлпера, к-рый знает, например, как этот вектор заполнить (ну, скажем, прочти чего-то из конфигурации, посчитай, найди и т.д. и т.п и положи в этот вектор).
Если предложенная модель не годится, то иногда удобнее сдублировать часть интерфейса вектора в его классе-контейнере. Например,
Код

class MyVeryImportantVector
{
typedef vector<SomeImportantCalss> TVectVeryImportant;
    TVectVeryImportant m_myVect;
public:
    typedef TVectVeryImportant::const_iterator const_iterator;
    typedef TVectVeryImportant::size_type size_type;

    const_iterator begin() const { return m_myVect.begin(); }
    const_iterator end  () const { return m_myVect.end(); }

    size_type     size () const { return m_myVect.size(); }

    const SomeImportantCalss& operator[size_t idx] const { return m_myVect[idx]; }
};
Немного громоздко, но никто с очень важным вектором не сделает более того, что позволено.

Добавлено @ 08:41
Цитата(chipset @ 8.4.2005, 16:51)
Если хочешь - можешь попробовать обернуть вектор в враппер запрещающий использовать изменяющие функции, хотя это конечно жуткий гемморой..

Во, блин, как плохо читать постинги через один! chipset уже эту идею предложил...

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