将const *存储在const向量中

Fin*_*nis 3 c++ const vector c++11 c++14

我必须处理的相关接口代码由两个函数组成,一个函数检索对象,另一个函数将对象作为矢量提交。问题是,检索函数返回const Object*,但是submit函数期望const vector<Object*>

我知道这可以用解决const_cast<Object*>,但是还有其他更清洁的方法吗?

这是演示问题的代码:

#include <vector>

//////////// REPRESENTATIVE INTERFACE IMPLEMENTATION, DO NOT TOUCH ///////
struct Object{};

class Interface{
    public:
    size_t getNumObjects() const {return 10;}
    const Object* getObject(size_t index) const {return nullptr;}
};
const Interface interface;

void submitObjects(const std::vector<Object*> &objects);
//////////////////////////////////////////////////////////////////////

// Task: take all objects from 'interface' and submit them to 'submitObjects'.

int main(){

    std::vector<const Object*> objects;
    for(size_t i = 0; i < interface.getNumObjects(); i++){
        const Object* object = interface.getObject(i);
        objects.push_back(object);
    }

    submitObjects(objects); // ERROR: no known conversion from 'vector<const Object *>' to 'const vector<Object *>'

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

解决这个问题的唯一方法是用制作objects一个,std::vector<Object*>然后插入对象objects.push_back(const_cast<Object*>(object));,但我觉得必须有一个更好的解决方案。

任何想法表示赞赏。


一些其他背景信息,为什么这是一个有效的问题: const vector<Object*>只能传递const Object*,如其所有getter重载所示,如此处所示:https : //de.cppreference.com/w/cpp/container/vector/operator_at

因此,vector<const Object*>几乎从未在接口中使用过。因此,结合了很多的想法const Object*在一个大const vector<Object*>是一个有效的概念,但似乎不可能没有建造const_cast

编辑:以上声明不正确,感谢您的澄清。 const std::vector<Object*> 可以产生非常量指针,因为我对指针常量的理解不正确。

Max*_*hof 7

您误解了文档/键入规则。如果你有T = Object*,那么const T是不是const Object*,但Object* const。这就是C和C ++的工作方式。

因此,您的断言“您不能从中获取可变对象const vector<Object*>是错误的。您不能做的是修改向量或元素的值(即更改指针)。但是访问器返回对的引用Object* const,因此仍可以修改指向的对象。 -对象:

void foo(const std::vector<int*>& v)
{
    (*v[0])++; // Increments the integer pointed to by the first vector element.
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/HGIb20

这仅仅是由于const没有传递。这是另一个示例:

struct X
{
    int* y;
};

void foo(const X& x)
{
    (*x.y)++;
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/NmCwGt


鉴于此,您所拥有的界面不允许您执行任何操作。您只能将指针传递给不可变的对象,而应该将指针传递给可变的对象(该submitObjects函数仅承诺不修改容器,但保留修改对象的权利)。这根本不可能。

const_cast如果您知道100%实际未将对象声明为创建对象的位置,则可能是一个有效的选项(如果这样做非常重要!)。但这既破坏了界面的要点,又是一种极其脆弱,笨拙的方法,在这种情况下您甚至不应该考虑。const


Gui*_*cot 5

您的接口返回指向常量对象的指针。您想将这些常量对象发送到需要可变对象的函数中。

这不仅涉及不确定的行为,还涉及惊喜。

想象一下实现该接口的那个函数保持有关对象的计算值,并在调用潜在的变异方法时将其标记为脏。确实有理由迫使指针返回常量对象。修改const对象会破坏类的不变性。

如果将常量发送给,submitObjects并且对象在此发生了变异,那么从某种意义上来说,这是一种谎言:接口将常量对象发送给您,然后对它们进行了变异。你违反了合同。

如果submitObjects不改变其自变量,则没有理由保持自变量可变。


为了避免对const的混淆,下面是一个指向可变数据的指针的const向量的示例:

// const std::vector<int*>
auto const cannot_erase_or_add = std::vector<int*>{
    new int{1},
    new int{2},
    new int{3}
};

// Error!
// cannot_erase_or_add.push_back(new int{4});

// Error!
// cannot_erase_or_add.clear();

// operator[] return int*, because it's a vector of int*
int* one = cannot_erase_or_add[0];

// totally legal, int*, no const there
*one = 2;
Run Code Online (Sandbox Code Playgroud)

另一方面,这是相反的:

// std::vector<int const*>
auto can_erase_or_add = std::vector<int const*>{
    new int{1},
    new int{2},
    new int{3}
};

// Works
can_erase_or_add.clear();

// Works
can_erase_or_add.push_back(new int{4});

// operator[] return int const*, because it's a vector of int const*
int const* four = can_erase_or_add[0];

// Can't do that, pointer to const
// *four = 2;
Run Code Online (Sandbox Code Playgroud)

  • @Finomnis该声明是错误的。 (2认同)