2

假设我有一个 array std::vector<Foo>,我想遍历我所有的 foos 并像这样做一些事情:

for (auto foo : vecFoo)
    foo.x = 10;

这最终什么都不做,因为它正在制作 vecFoo 内容的本地副本,而不是对其的引用。正确的循环如下:

for (auto& foo : vecFoo)
    foo.x = 10;

这是我现在犯过几次的错误,所以我想找到一个解决方案,当我出错时会抓住我。我会对可以对结构执行的操作或可以打开的警告标志感到满意。我尝试将Foo' 的复制构造函数设为私有,但最终我无法执行push_backor emplace_back,这显然不是我想要的。

4

3 回答 3

4

根本问题的答案是学习。如果你再犯几次错误,你最终会从经验中学习。

至于您的特定情况的语言技巧,您可以完全控制存储在容器中的类型,您可以提供nothrow移动构造函数并禁用复制构造。这将需要使用emplace_back(或使用移动语义push_back)。

尽管如此,这只是在这种特殊情况下触发错误的一种方式,但是如果您存储的任何类型不是 100% 在您的控制之下(即不能禁用复制构造或添加移动构造,或者无法实现 nothrow 移动构造函数 -不能保证不会丢)那你就倒霉了,这就引出了第一句话:learn to use references

于 2012-09-04T16:27:47.317 回答
1

我要求的是一种使该副本对我的班级无效的方法,这样就不会有机会犯这样的错误。

C++11 使您的类不可复制变得容易。只需删除复制构造函数/赋值运算符(假设您的编译器支持 C++11 功能):

class SomeClass
{
public:
  SomeClass(const SomeClass &) = delete;
  SomeClass &operator=(const SomeClass &) = delete;

...
};

任何调用复制构造函数的尝试都会产生编译器错误。如果您使用尚不支持此语法的 Visual Studio,则必须为此使用标准 C++03 习惯用法。即,私下声明复制构造函数。


我不能再在向量中使用我的结构,因为它不能被复制到向量中。

你当然可以。您只是不能使用需要复制的功能。你必须用 and 替换你对andpush_backinsert使用。emplace_backemplace

请记住:如果您声明了复制构造函数和赋值运算符,即使只是删除它们,您也必须手动声明移动构造函数/赋值运算符。当然,您可以使用= default语法。

于 2012-09-04T16:59:08.327 回答
1

这是我现在犯过几次的错误,所以我想找到一个解决方案,当我出错时会抓住我。

根据我的经验,最好的解决方案是训练自己始终将对象声明为const默认值。这使得尝试修改它们成为编译器检查错误。一旦你这样做了,当你忘记偏离它以使对象可写时,编译器将为你捕获这样的声明:

// This is what my hands write by default:
int const x = 42;

我试着总是这样写。然后,每当我在代码中看到以下内容时:

int y =  42;

我的想法试图弄清楚该变量是否实际上应该是可修改的。您可以将这种想法应用于您的循环示例,因为幸运的是,C++11 也允许这种用于 range-for 循环:

for (auto const i : vecFoo)
    i.foo = 10; // error

当然,这仅在您训练自己自动完成const所有操作后才有效。

我同意这远非完美,需要大量练习。正如一些人反复指出的那样,最好的解决方案是 C++const默认考虑声明(实际上至少对于 lambda 捕获的值是这种情况),但那艘船已经航行了。

于 2012-09-04T16:17:12.600 回答