портирование кода с MSVC на gcc
От: abrec Россия  
Дата: 19.08.09 15:33
Оценка:
Здравствуйте!
Писал проект на MSVC с галочкой в мозге, что возможно надо будет портировать на linux. Сбылось.
Поставил openSUSE 11, codeblocks, boost_1_39_0.
Началось.... Нашел у себя несколько явных косяков
Помогите разобраться.
class CINIItem
{
private:
    std::string m_strSectionName;
    std::string m_strValueName;
    std::string m_strValue;
public:
    CINIItem(const char* pszSectionName, const char* pszValueName,    const char* pszValue);
    ...
    const std::string& GetValue()const { return m_strValue; } ;
    void SetValue(const std::string& strNewValue) { m_strValue = strNewValue; };
        ...
    typedef std::set< CINIItem, CINIItem::Less > INIITEMS;
};
class CINIData
{
protected:
    CINIItem::INIITEMS m_INIItems;
public:
    CINIData(){};
        ...
    bool SetValue(const char* pszSectionName, const char* pszValueName, const long& lValue)
    {
        CINIItem item(pszSectionName, pszValueName, "");
        CINIItem::INIITEMS::iterator iter = m_INIItems.find(item);
        if(iter == m_INIItems.end()) return false;
        std::stringstream sValue;
        sValue << lValue;
        (*iter).SetValue(sValue.str());//здесь ошибка!!!!
//../Public/Include/inidata.h|165|ошибка: нет подходящей функции для вызова ‘CINIItem::SetValue(std::basic_string<char, std::char_traits<char>, std::allocator<char> >) const’|
//../Public/Include/inidata.h|50|замечание: претенденты: void CINIItem::SetValue(const std::string&) <near match>|
        return true;
    };
        ...
};
Re: портирование кода с MSVC на gcc
От: Аноним  
Дата: 19.08.09 15:45
Оценка:
std::ostringstream ?
Re[2]: портирование кода с MSVC на gcc
От: abrec Россия  
Дата: 19.08.09 15:49
Оценка: :)
Здравствуйте, Аноним, Вы писали:

А>std::ostringstream ?


не понял. но не помогло.
Re[3]: портирование кода с MSVC на gcc
От: Аноним  
Дата: 19.08.09 15:52
Оценка:
#include <sstream>

class CINIItem
{
private:
    std::string m_strSectionName;
    std::string m_strValueName;
    std::string m_strValue;
public:
    CINIItem(const char* pszSectionName, const char* pszValueName,    const char* pszValue);
    ...
    const std::string& GetValue()const { return m_strValue; } ;
    void SetValue(const std::string& strNewValue) { m_strValue = strNewValue; };
        ...
    typedef std::set< CINIItem, CINIItem::Less > INIITEMS;
};
class CINIData
{
protected:
    CINIItem::INIITEMS m_INIItems;
public:
    CINIData(){};
        ...
    bool SetValue(const char* pszSectionName, const char* pszValueName, const long& lValue)
    {
        CINIItem item(pszSectionName, pszValueName, "");
        CINIItem::INIITEMS::iterator iter = m_INIItems.find(item);
        if(iter == m_INIItems.end()) return false;
//        std::stringstream sValue;
        std::ostringstream sValue;
        sValue << lValue;
        (*iter).SetValue(sValue.str());
        return true;
    };
        ...
};
Re[4]: портирование кода с MSVC на gcc
От: abrec Россия  
Дата: 19.08.09 15:53
Оценка:
Здравствуйте, Аноним, Вы писали:

А>
А>#include <sstream>

А>class CINIItem
А>{
А>private:
А>    std::string m_strSectionName;
А>    std::string m_strValueName;
А>    std::string m_strValue;
А>public:
А>    CINIItem(const char* pszSectionName, const char* pszValueName,    const char* pszValue);
А>    ...
А>    const std::string& GetValue()const { return m_strValue; } ;
А>    void SetValue(const std::string& strNewValue) { m_strValue = strNewValue; };
А>        ...
А>    typedef std::set< CINIItem, CINIItem::Less > INIITEMS;
А>};
А>class CINIData
А>{
А>protected:
А>    CINIItem::INIITEMS m_INIItems;
А>public:
А>    CINIData(){};
А>        ...
А>    bool SetValue(const char* pszSectionName, const char* pszValueName, const long& lValue)
А>    {
А>        CINIItem item(pszSectionName, pszValueName, "");
А>        CINIItem::INIITEMS::iterator iter = m_INIItems.find(item);
А>        if(iter == m_INIItems.end()) return false;
А>//        std::stringstream sValue;
А>        std::ostringstream sValue;
А>        sValue << lValue;
А>        (*iter).SetValue(sValue.str());
А>        return true;
А>    };
А>        ...
А>};
не не не не помогло :)
А>
Re[5]: портирование кода с MSVC на gcc
От: Аноним  
Дата: 19.08.09 15:57
Оценка:
че? !!!!0 == true сообщения об ошибках покажи
Re[6]: портирование кода с MSVC на gcc
От: abrec Россия  
Дата: 19.08.09 15:59
Оценка:
Здравствуйте, Аноним, Вы писали:

А>че? !!!!0 == true сообщения об ошибках покажи


//../Public/Include/inidata.h|165|ошибка: нет подходящей функции для вызова ‘CINIItem::SetValue(std::basic_string<char, std::char_traits<char>, std::allocator<char> >) const’|
//../Public/Include/inidata.h|50|замечание: претенденты: void CINIItem::SetValue(const std::string&) <near match>|
Re: портирование кода с MSVC на gcc
От: Sergey Россия  
Дата: 19.08.09 15:59
Оценка: 2 (1) +1
Здравствуйте, abrec, Вы писали:

A>Писал проект на MSVC с галочкой в мозге, что возможно надо будет портировать на linux. Сбылось.

A>Поставил openSUSE 11, codeblocks, boost_1_39_0.
A>Началось.... Нашел у себя несколько явных косяков
A>Помогите разобраться.
A>
A>//../Public/Include/inidata.h|165|ошибка: нет подходящей функции для вызова ‘CINIItem::SetValue(std::basic_string<char, std::char_traits<char>, std::allocator<char> >) const’|
A>//../Public/Include/inidata.h|50|замечание: претенденты: void CINIItem::SetValue(const std::string&) <near match>|
A>


Ну написано же — константность мешает. Почему VC разрешает изменять элемент множества через итератор и что при этом происходит с множеством и с итератором — хз.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[2]: портирование кода с MSVC на gcc
От: abrec Россия  
Дата: 19.08.09 16:00
Оценка:
Здравствуйте, Sergey, Вы писали:

S>Здравствуйте, abrec, Вы писали:


A>>Писал проект на MSVC с галочкой в мозге, что возможно надо будет портировать на linux. Сбылось.

A>>Поставил openSUSE 11, codeblocks, boost_1_39_0.
A>>Началось.... Нашел у себя несколько явных косяков
A>>Помогите разобраться.
A>>
A>>//../Public/Include/inidata.h|165|ошибка: нет подходящей функции для вызова ‘CINIItem::SetValue(std::basic_string<char, std::char_traits<char>, std::allocator<char> >) const’|
A>>//../Public/Include/inidata.h|50|замечание: претенденты: void CINIItem::SetValue(const std::string&) <near match>|
A>>


S>Ну написано же — константность мешает. Почему VC разрешает изменять элемент множества через итератор и что при этом происходит с множеством и с итератором — хз.


так вроде есть отдельный const_iterator.???
Re: портирование кода с MSVC на gcc
От: Sni4ok  
Дата: 19.08.09 16:02
Оценка:
Здравствуйте, abrec, Вы писали:

бага msvc- что скомпилила, по итератеру сета нельзя менять значение, ибо сет может стать невалидным.
Re[2]: портирование кода с MSVC на gcc
От: abrec Россия  
Дата: 19.08.09 16:03
Оценка:
Здравствуйте, Sni4ok, Вы писали:

S>Здравствуйте, abrec, Вы писали:


S>бага msvc- что скомпилила, по итератеру сета нельзя менять значение, ибо сет может стать невалидным.


тобишь надо взять элемент изменить и обратно в сет засунуть?
Re[3]: портирование кода с MSVC на gcc
От: Sni4ok  
Дата: 19.08.09 16:04
Оценка: 3 (1)
Здравствуйте, abrec, Вы писали:

A>так вроде есть отдельный const_iterator.???


константый итератор нельзя удалить, неконстантный можно, чтобы поменять значение в set'е- сначала удалите по итератеру, и потом добавте новое значение.
Re[6]: портирование кода с MSVC на gcc
От: Аноним  
Дата: 19.08.09 16:05
Оценка:
!!!!true == true
Re[4]: портирование кода с MSVC на gcc
От: abrec Россия  
Дата: 19.08.09 16:06
Оценка:
Здравствуйте, Sni4ok, Вы писали:

S>Здравствуйте, abrec, Вы писали:


A>>так вроде есть отдельный const_iterator.???


S>константый итератор нельзя удалить, неконстантный можно, чтобы поменять значение в set'е- сначала удалите по итератеру, и потом добавте новое значение.


в принципе логично. ведь он там пересортировывается постоянно. как же vc пропустила?
Re: портирование кода с MSVC на gcc
От: Юрий Жмеренецкий ICQ 380412032
Дата: 19.08.09 16:06
Оценка: 67 (3)
Здравствуйте, abrec, Вы писали:

A>Здравствуйте!

A>Писал проект на MSVC с галочкой в мозге, что возможно надо будет портировать на linux. Сбылось.
A>Поставил openSUSE 11, codeblocks, boost_1_39_0.
A>Началось.... Нашел у себя несколько явных косяков
A>Помогите разобраться.
A>
A>class CINIItem
A>{
A>private:
A>    std::string m_strSectionName;
A>    std::string m_strValueName;
A>    std::string m_strValue;
A>public:
A>    CINIItem(const char* pszSectionName, const char* pszValueName,    const char* pszValue);
A>    ...
A>    const std::string& GetValue()const { return m_strValue; } ;
A>    void SetValue(const std::string& strNewValue) { m_strValue = strNewValue; };
A>        ...
A>    typedef std::set< CINIItem, CINIItem::Less > INIITEMS;
A>};
A>class CINIData
A>{
A>protected:
A>    CINIItem::INIITEMS m_INIItems;
A>public:
A>    CINIData(){};
A>        ...
A>    bool SetValue(const char* pszSectionName, const char* pszValueName, const long& lValue)
A>    {
A>        CINIItem item(pszSectionName, pszValueName, "");
A>        CINIItem::INIITEMS::iterator iter = m_INIItems.find(item);
A>        if(iter == m_INIItems.end()) return false;
A>        std::stringstream sValue;
A>        sValue << lValue;
A>        (*iter).SetValue(sValue.str());//здесь ошибка!!!!
A>//../Public/Include/inidata.h|165|ошибка: нет подходящей функции для вызова ‘CINIItem::SetValue(std::basic_string<char, std::char_traits<char>, std::allocator<char> >) const’|
A>//../Public/Include/inidata.h|50|замечание: претенденты: void CINIItem::SetValue(const std::string&) <near match>|
A>        return true;
A>    };
A>        ...
A>};
A>


Это "правильная" ошибка, в MSVC баг связанный с багом в стандарте: разрешено вызвать неконстантные методы для результата разыменования итераторов std::set, хотя по логике ключи иммутабельны. Для изменения значения ключа нужно удалить элемент со старым значением и вставить с измененным.
Re[3]: портирование кода с MSVC на gcc
От: Sni4ok  
Дата: 19.08.09 16:09
Оценка: 2 (1)
Здравствуйте, abrec, Вы писали:

A>тобишь надо взять элемент изменить и обратно в сет засунуть?


угу, но если вы уверены, что ваша неконстантная операция не может повлиять на сортировку(не изменяете полей от которых зависит компаратор), то лучше воспользоваться конст-кастом, поскольку удаление и обратная вставка- всётаки не дешёвая операция.
Re[4]: портирование кода с MSVC на gcc
От: abrec Россия  
Дата: 19.08.09 16:15
Оценка:
Здравствуйте, Sni4ok, Вы писали:

S>Здравствуйте, abrec, Вы писали:


A>>тобишь надо взять элемент изменить и обратно в сет засунуть?


S>угу, но если вы уверены, что ваша неконстантная операция не может повлиять на сортировку(не изменяете полей от которых зависит компаратор), то лучше воспользоваться конст-кастом, поскольку удаление и обратная вставка- всётаки не дешёвая операция.

спасибо const_cast ом вышел из ситуевины.
1. барьер пройден
Re[7]: портирование кода с MSVC на gcc
От: Аноним  
Дата: 19.08.09 16:16
Оценка:
извини, я разглядел наконец, что компилятор к другому совсем цеплялся.
Re[2]: портирование кода с MSVC на gcc
От: Кодт Россия  
Дата: 19.08.09 17:03
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>Это "правильная" ошибка, в MSVC баг связанный с багом в стандарте: разрешено вызвать неконстантные методы для результата разыменования итераторов std::set, хотя по логике ключи иммутабельны. Для изменения значения ключа нужно удалить элемент со старым значением и вставить с измененным.


То есть, value_type — не typedef const key_type, а просто key_type ?!
(По аналогии с map — typedef pair<const key_type,mapped_type> value_type)

Полез в Стандарт изумляться...
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[5]: портирование кода с MSVC на gcc
От: Кодт Россия  
Дата: 19.08.09 17:03
Оценка: 3 (1)
Здравствуйте, abrec, Вы писали:

S>>угу, но если вы уверены, что ваша неконстантная операция не может повлиять на сортировку(не изменяете полей от которых зависит компаратор), то лучше воспользоваться конст-кастом, поскольку удаление и обратная вставка- всётаки не дешёвая операция.

A>спасибо const_cast ом вышел из ситуевины.
A>1. барьер пройден

Может, хотя бы проверку делать?
template<class Set>
void set_update(Set& cont, Set::iterator it, Set::value_type value)
{
    Set::value_compare cmp = cont.value_comp();
    if(!cmp(*it,value) && !cmp(value,*it)) // value == *it
        return;

    Set::iterator left, right; // можно обойтись вообще одним итератором (а при известной ловкости - даже только it)
    
    bool const left_ok  = (left=it)==cont.begin()  || cmp()(*(--left),value); // *left < value
    bool const right_ok = ++(right=it)==cont.end() || cmp()(value,*right);    // value < *right
    // для multiset нужно проверять !cmp(value,*left) и !cmp(*right,value),
    // т.е. *left <= value и value <= *right
    
    if(left_ok && right_ok)
        const_cast<Set::key_type&>(*it) = value; // хак
    else // тормоза, зато честно
    {
        cont.erase(it);
        cont.insert(value);
    }
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[6]: портирование кода с MSVC на gcc
От: abrec Россия  
Дата: 19.08.09 17:11
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, abrec, Вы писали:


S>>>угу, но если вы уверены, что ваша неконстантная операция не может повлиять на сортировку(не изменяете полей от которых зависит компаратор), то лучше воспользоваться конст-кастом, поскольку удаление и обратная вставка- всётаки не дешёвая операция.

A>>спасибо const_cast ом вышел из ситуевины.
A>>1. барьер пройден

К>Может, хотя бы проверку делать?

К>
К>template<class Set>
К>void set_update(Set& cont, Set::iterator it, Set::value_type value)
К>{
К>    Set::value_compare cmp = cont.value_comp();
К>    if(!cmp(*it,value) && !cmp(value,*it)) // value == *it
К>        return;

К>    Set::iterator left, right; // можно обойтись вообще одним итератором (а при известной ловкости - даже только it)
    
К>    bool const left_ok  = (left=it)==cont.begin()  || cmp()(*(--left),value); // *left < value
К>    bool const right_ok = ++(right=it)==cont.end() || cmp()(value,*right);    // value < *right
К>    // для multiset нужно проверять !cmp(value,*left) и !cmp(*right,value),
К>    // т.е. *left <= value и value <= *right
    
К>    if(left_ok && right_ok)
К>        const_cast<Set::key_type&>(*it) = value; // хак
К>    else // тормоза, зато честно
К>    {
К>        cont.erase(it);
К>        cont.insert(value);
К>    }
К>}
К>


Спасибо!
В принципе там в сет

//Предикат для сравнения двух ключей
    struct Less
    {
        bool operator()(
                const CINIItem &l, 
                const CINIItem &r) const
        {         
            if(l.m_strSectionName == r.m_strSectionName)
                return l.m_strValueName < r.m_strValueName;
            else
                return l.m_strSectionName < r.m_strSectionName;
        };
    };

так что изменение value не имеет значения
Re[7]: портирование кода с MSVC на gcc
От: Кодт Россия  
Дата: 19.08.09 18:25
Оценка: 2 (1)
Здравствуйте, abrec, Вы писали:

A> так что изменение value не имеет значения


Почему бы сразу не сделать map< pair<string,string>, string >
где ключ — это пара (секция,имя), а значение — это, собственно, значение?

Вместо стандартной пары можешь написать собственный класс CINIKey... Хотя это незачем, т.к. над pair<...> уже определены все нужные операторы.

Это и идеологически верно, и итерировать позволяет по-прежнему (элементы мапа — map<K,V>::value_type — pair<const K,V>).
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[3]: портирование кода с MSVC на gcc
От: Юрий Жмеренецкий ICQ 380412032
Дата: 19.08.09 19:10
Оценка: 60 (1)
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Юрий Жмеренецкий, Вы писали:


ЮЖ>>Это "правильная" ошибка, в MSVC баг связанный с багом в стандарте: разрешено вызвать неконстантные методы для результата разыменования итераторов std::set, хотя по логике ключи иммутабельны. Для изменения значения ключа нужно удалить элемент со старым значением и вставить с измененным.


К>То есть, value_type — не typedef const key_type, а просто key_type ?!

К>(По аналогии с map — typedef pair<const key_type,mapped_type> value_type)

К>Полез в Стандарт изумляться...


В C++ Standard Library Defect Report List есть подробное описание дефекта. Примечательно то, что исправление достаточно хитрое и затрагивает все ассоциативные контейнеры:

103. set::iterator is required to be modifiable, but this allows modification of keys

...
23.1 [container.requirements] actually requires that iterator type pointing to T (table 65). Disallowing user modification of keys by changing the standard to require an iterator for associative container to be the same as const_iterator would be overkill since that will unnecessarily significantly restrict the usage of associative container. A class to be used as elements of set, for example, can no longer be modified easily without either redesigning the class (using mutable on fields that have nothing to do with ordering), or using const_cast, which defeats requiring iterator to be const_iterator. The proposed solution goes in line with trusting user knows what he is doing.
...
Proposed resolution:

Add the following to 23.1.4 [associative.reqmts] at the indicated location:

At the end of paragraph 3: "For any two keys k1 and k2 in the same container, calling comp(k1, k2) shall always return the same value."

At the end of paragraph 5: "Keys in an associative container are immutable."

At the end of paragraph 6: "For associative containers where the value type is the same as the key type, both iterator and const_iterator are constant iterators. It is unspecified whether or not iterator and const_iterator are the same type."

Rationale:

Several arguments were advanced for and against allowing set elements to be mutable as long as the ordering was not effected. The argument which swayed the LWG was one of safety; if elements were mutable, there would be no compile-time way to detect of a simple user oversight which caused ordering to be modified. There was a report that this had actually happened in practice, and had been painful to diagnose. If users need to modify elements, it is possible to use mutable members or const_cast.

Re[8]: портирование кода с MSVC на gcc
От: abrec Россия  
Дата: 20.08.09 03:46
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, abrec, Вы писали:


A>> так что изменение value не имеет значения


К>Почему бы сразу не сделать map< pair<string,string>, string >

К>где ключ — это пара (секция,имя), а значение — это, собственно, значение?

К>Вместо стандартной пары можешь написать собственный класс CINIKey... Хотя это незачем, т.к. над pair<...> уже определены все нужные операторы.


К>Это и идеологически верно, и итерировать позволяет по-прежнему (элементы мапа — map<K,V>::value_type — pair<const K,V>).


Спасибо. Недотумкал как то.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.