在const函数中更改映射内容

Changing a map content inside const function

本文关键字:映射 const 函数      更新时间:2023-10-16

我使用QMap::find()const QMap获得一个迭代器,并且通过该迭代器,我可以更改映射的内容。在我看来,这违反了对象的逻辑恒定性。我错了吗?

这是允许的,因为编译器不能识别什么被改变,因为Qt API?

void OpticalTrackingSystem::UpdateTrackability(const QUuid &uid) const
{
  // m_ObjectsToTrack is a member, therefore const
  ObjectMap::iterator it = m_ObjectsToTrack.find(uid);
  it.value().m_Trackable = true; // assignment to const!
  it.value().m_Moved = false;
}

如果有关系,我的编译器是MSVC。

Edit: ObjectMap定义为

struct ObjectProperties
{
    ObjectProperties(const ObjectToTrack &obj)
        : m_Obj(obj) { m_Trackable = false; m_Moved = false; }
    ObjectToTrack m_Obj;
    bool m_Trackable;
    bool m_Moved;
};
typedef QMap<QUuid, ObjectProperties> ObjectMap; 

const增强了数据隐藏和封装功能,以提供完整的编译时安全性。

c++只支持一层常量。在您的示例中,这意味着您的函数不能添加、删除或替换映射中的元素。然而,操纵其成员是公平的游戏。

QMap同时具有const和非const find方法:

      iterator find(const Key & key)
const_iterator find(const Key & key) const

就像std::map:

      iterator find (const key_type& k);
const_iterator find (const key_type& k) const;

QMap迭代器在value()的constness上有所不同:

      T& QMap::      iterator::value() const;
const T& QMap::const_iterator::value() const;

所以不能通过返回的迭代器操作这些值。但是你将返回的迭代器赋值给ObjectMap::iterator——我预计此时会出现错误,但是没有ObjectMap及其迭代器的定义,我无法测试它。

显然下面的MCVE演示了一个编译时错误:

#include <QMap>
int main()
{
    const QMap<int,float> m{{1, 1.0}, {5, 5.0}};
    auto it = m.find(1);
    it.value() = 2.0;
    //         ^
    // error: assignment of read-only location
    //       ‘it.QMap<Key, T>::const_iterator::value<int, float>()’
}

显式地赋值迭代器会给出另一个预期错误:

#include <QMap>
int main()
{
    const QMap<int,float> m{{1, 1.0}, {5, 5.0}};
    QMap<int,float>::iterator it = m.find(1);
    //                                     ^
    // error: conversion from ‘QMap<int, float>::const_iterator’
    //        to non-scalar type ‘QMap<int, float>::iterator’ requested
    it.value() = 2.0;
}

(我在两种情况下都使用g++ -std=c++11 -Wall -Wextra -fPIC $(pkg-config --cflags Qt5Core)编译)

编辑

由于问题中没有适当的示例,我试图推断缺失的声明。但是当我尝试编译这个时,我仍然从gcc得到所需的错误:

#include <QMap>
#include <QUuid>
struct ObjectToTrack
{
};
struct ObjectProperties
{
    ObjectProperties(const ObjectToTrack &obj)
        : m_Obj(obj), m_Trackable(), m_Moved() {}
    ObjectToTrack m_Obj;
    bool m_Trackable;
    bool m_Moved;
};
typedef QMap<QUuid, ObjectProperties> ObjectMap;
struct OpticalTrackingSystem
{
    ObjectMap m_ObjectsToTrack;
    void UpdateTrackability(const QUuid &uid) const;
};
void OpticalTrackingSystem::UpdateTrackability(const QUuid &uid) const
{
  ObjectMap::iterator it = m_ObjectsToTrack.find(uid);
  //                                                ^
  // error: conversion from ‘QMap<QUuid, ObjectProperties>::const_iterator’ to
  //        non-scalar type ‘QMap<QUuid, ObjectProperties>::iterator’ requested
  it.value().m_Trackable = true;
  it.value().m_Moved = false;
}

我的结论是问题中的代码没有问题。要么是编译器有bug,要么是问题中缺少了与我上面的重构不同的重要信息。