假设我有一个数组std::vector<Foo>
,我想迭代我所有的foos并按照这样做做事:
for (auto foo : vecFoo)
foo.x = 10;
这最终无所事事,因为它正在制作vecFoo内容的本地副本而不是对它的引用。正确的循环如下:
for (auto& foo : vecFoo)
foo.x = 10;
这是我现在做过几次的错误,所以我想找到一个解决方案,当我弄错的时候会抓住我。对于我可以对结构做的事情或者我可以打开的警告标志,我会很高兴。我已经尝试将Foo
的复制构造函数设为私有,但后来我最终无法执行push_back
或emplace_back
,这显然不是我想要的。
答案 0 :(得分:4)
潜在问题的答案是学习。如果你犯了几次错误,你最终会从经验中学习。
对于您的特定情况的语言技巧,您可以完全控制存储在容器中的类型,您可以提供nothrow
移动构造函数并禁用复制构造。这需要使用emplace_back
(或移动语义和push_back
)。
尽管如此,这只是在这种特殊情况下触发错误的一种方式,但是如果您存储的任何类型不是100%在您的控制之下(即无法禁用复制构造或添加移动构造,或者无法实现nothrow移动构造函数 - 无法保证它不会抛出)然后你运气不好,这导致了第一句话:学会使用引用
答案 1 :(得分: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捕获的值,这个是)但是航行了。
答案 2 :(得分:1)
我所要求的是使该副本对我的班级无效的方法,以便不会犯这样的错误。
C ++ 11使您可以轻松地使您的类无法复制。只需删除复制构造函数/赋值运算符(假设您的编译器支持该C ++ 11特性):
class SomeClass
{
public:
SomeClass(const SomeClass &) = delete;
SomeClass &operator=(const SomeClass &) = delete;
...
};
任何调用复制构造函数的尝试都将产生编译器错误。如果您使用的是尚不支持此语法的Visual Studio,则必须使用标准C ++ 03惯用法。即,私下声明复制构造函数。
我无法再在向量中使用我的结构,因为它无法复制到向量中。
当然可以。您无法使用需要复制的功能。您必须将push_back
和insert
的使用替换为emplace_back
和emplace
。
请记住:如果您声明了复制构造函数和赋值运算符,即使只是删除它们,您必须手动声明 move 构造函数/赋值运算符。当然,您可以使用= default
语法。