【问题标题】:Why can't you put a const object into a STL container?为什么不能将 const 对象放入 STL 容器中?
【发布时间】:2011-12-31 00:04:13
【问题描述】:

请参阅下面的代码 - 我正在尝试将 const 对象放入向量中。我知道答案是“STL 容器要求对象是可分配的和可复制的”,但是,在没有引用标准的情况下,谁能解释这样做的问题是什么?我不明白为什么不能复制这样的类(除了 c++ 不允许这样做)。

它只是一个不允许更改的存储值 - 为什么不能将它放入向量中简单地创建另一个对象?

#include <vector>

// Attempt 1
// /home/doriad/Test/Test.cxx:3:8: error: non-static const member ‘const int MyClass::x’, can’t use default assignment operator

// struct MyClass
// {
//   int const x;
//   MyClass(int x): x(x) {}
// };
// 
// int main()
// {
//   std::vector<MyClass> vec;
//   vec.push_back(MyClass(3));
//   return 0;
// }

// Attempt 2
// /home/doriad/Test/Test.cxx:28:23: error: assignment of read-only member ‘MyClass::x’
struct MyClass
{
  int const x;
  MyClass(int x): x(x) {}
  MyClass& operator= (const MyClass& other)
  {
    if (this != &other)
    {
      this->x = other.x;
    }

    return *this;
  }
};

int main()
{
  std::vector<MyClass> vec;
  vec.push_back(MyClass(3));
  return 0;
}

编辑:

使用 std::set 和 std::list 可以做到这一点。我猜是 std::vector 中的 sort() 函数使用了赋值。这不是UB吧?

#include <set>

// Attempt 1
struct MyClass
{
  int const x;
  MyClass(int x): x(x) {}
  bool operator< (const MyClass &other) const;
};

bool MyClass::operator<(const MyClass &other) const
{
  if(this->x < other.x)
  {
    return true;
  }
  else if (other.x < this->x)
  {
    return false;
  }

}


int main()
{
  std::set<MyClass> container;
  container.insert(MyClass(3));
  return 0;
}

【问题讨论】:

  • 请查看我使用 std::set 而不是 std::vector 的编辑。这样可以吗?
  • @David :在 C++03 中,像这样使用 std::set&lt;&gt; 仍然是错误的——§23.1/3 规定元素类型必须是可复制构造的 和 i> 可分配的。在 C++11 中,您的代码格式正确,但您的 std::set&lt;&gt; 实例将不可分配,因为 MyClass 不可分配。 (另外,只是半相关的:你的operator&lt; 实现被破坏了,因为如果this-&gt;x == other.x 它不会返回任何值)。
  • ildjarn - 你是对的操作员

标签: c++


【解决方案1】:

EDIT2:(删除一堆不必工作的东西)C ++ 11标准规定vectordequeinsert方法(以及push_back的默认实现)那件事)要求值类型为CopyAssignable,即该值支持:

t= v;

默认情况下,具有const 成员的类和结构不是CopyAssignable,因此您想要做的事情不会起作用。

此文档(n3173) 解释了各种容器要求。

【讨论】:

  • MSN:那我该怎么做才能让它工作呢?它迫使我实现赋值运算符,但我不能做赋值,因为它是 const!
  • @David :避免使用 const 数据成员——如果你的类提供了正确的 const 正确的 getter,它们就毫无用处。
  • @David :相反,它是惯用的——私有非常量数据成员,公共 const getter。任何基本的 C++ 书籍都会对此提出建议。
  • 好吧,你不能同时拥有:常量数据成员和可分配对象。毕竟,赋值确实会改变常量数据成员。
  • @MSN:容器中使用的类型必须是Assignable,这意味着它需要复制构造函数和赋值运算符。您的编译器是否正在验证 Assignable 概念是一个不同的问题,但我敢打赌,如果您尝试从 vector 中间插入/删除一个元素并且存储的类型不提供赋值运算符,那么您的编译器也将无法编译。
【解决方案2】:

一种可能的解决方案是将指向对象的指针存储在向量中,因为指针是可分配的和可复制构造的。

另一种可能的解决方案是在不使用 const 关键字的情况下声明 x,但确保不能通过封装对其进行修改(即,您应该将其声明为私有,并且不要从构造函数之外的任何地方进行修改)..

【讨论】:

    【解决方案3】:

    当您将 MyClass 类型的对象放入 std::vector 时,vector 将复制该对象而不是您传递给它的对象。

    【讨论】:

    • 当然,这是有道理的。但是为什么它不能复制一个具有 const 值的对象呢?它应该能够创建一个具有相同 const 值的新对象,不是吗?
    • @David :当然可以,但是您仍然缺少“可分配”要求。
    猜你喜欢
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 2013-11-04
    • 2011-04-13
    • 1970-01-01
    • 2013-11-22
    • 2013-07-21
    相关资源
    最近更新 更多