构造结构&
我在弄清楚 const 在特定情况下如何应用时遇到了一些困难。 这是我的代码:
struct Widget
{
Widget():x(0), y(0), z(0){}
int x, y, z;
};
struct WidgetHolder //Just a simple struct to hold four Widgets.
{
WidgetHolder(Widget a, Widget b, Widget c, Widget d): A(a), B(b), C(c), D(d){}
Widget& A;
Widget& B;
Widget& C;
Widget& D;
};
class Test //This class uses four widgets internally, and must provide access to them externally.
{
public:
const WidgetHolder AccessWidgets() const
{
//This should return our four widgets, but I don't want anyone messing with them.
return WidgetHolder(A, B, C, D);
}
WidgetHolder AccessWidgets()
{
//This should return our four widgets, I don't care if they get changed.
return WidgetHolder(A, B, C, D);
}
private:
Widget A, B, C, D;
};
int main()
{
const Test unchangeable;
unchangeable.AccessWidgets().A.x = 1; //Why does this compile, shouldn't the Widget& be const?
}
基本上,我有一个名为 test 的类。 它在内部使用四个小部件,我需要它返回这些小部件,但如果 test 被声明为 const,我希望小部件也返回 const。
有人可以向我解释一下为什么 main() 中的代码可以编译吗?
非常感谢。
I'm having a little trouble figuring out exactly how const applies in a specific case. Here's the code I have:
struct Widget
{
Widget():x(0), y(0), z(0){}
int x, y, z;
};
struct WidgetHolder //Just a simple struct to hold four Widgets.
{
WidgetHolder(Widget a, Widget b, Widget c, Widget d): A(a), B(b), C(c), D(d){}
Widget& A;
Widget& B;
Widget& C;
Widget& D;
};
class Test //This class uses four widgets internally, and must provide access to them externally.
{
public:
const WidgetHolder AccessWidgets() const
{
//This should return our four widgets, but I don't want anyone messing with them.
return WidgetHolder(A, B, C, D);
}
WidgetHolder AccessWidgets()
{
//This should return our four widgets, I don't care if they get changed.
return WidgetHolder(A, B, C, D);
}
private:
Widget A, B, C, D;
};
int main()
{
const Test unchangeable;
unchangeable.AccessWidgets().A.x = 1; //Why does this compile, shouldn't the Widget& be const?
}
Basically, I have a class called test. It uses four widgets internally, and I need it to return these, but if test was declared const, I want the widgets returned const also.
Can someone explain to me why the code in main() compiles?
Thank you very much.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您的
WidgetHolder
将保存无效的引用(指针)。 您将堆栈上的对象传递给构造函数,然后保存对其(临时)地址的引用。 这肯定会打破。您应该只将引用分配给与引用本身具有相同(或更长)生命周期的对象。
如果必须保留引用,请将引用传递给构造函数。 更好的是,根本不要保留参考资料,只需制作副本即可。
Your
WidgetHolder
is going to hold invalid references (pointers). You are passing objects on the stack to the constructor and then holding references to their (temporary) addresses. This is guaranteed to break.You should only assign references to objects with the same (or greater) lifetime as the reference itself.
Pass references to the constructor if you must hold references. Even better, don't hold the references at all and just make the copies.
您需要创建一个专门用于保存 const Widget& 的新类型。 对象。 即:
您现在将收到以下错误(在 gcc 4.3 中):
在带有迭代器的标准库中使用了类似的习惯用法,即:
You need to create a new type specifically for holding const Widget& objects. Ie:
You will now get the following error (in gcc 4.3):
A similar idiom is used in the standard library with iterators ie:
unchangeable.AccessWidgets():
此时,您正在创建一个 WidgetHolder 类型的新对象。
该对象不受 const 保护。
您还在 WidgetHolder 中创建新的小部件,而不是对 Wdiget 的引用。
unchangeable.AccessWidgets():
At this point, you are creating a new object of type WidgetHolder.
This object is not protected by const.
You are also creating new widgets in the WidgetHolder and not references to the Wdiget.
最初的查询是如果包含的类是 const,如何将 WidgetHolder 作为 const 返回。 C++ 使用 const 作为函数签名的一部分,因此同一函数可以有 const 版本和非 const 版本。 当实例不是const时,调用none const;当实例是const时,调用const。 因此,解决方案是通过函数而不是直接访问小部件持有者中的小部件。 我在下面创建了一个更简单的示例,我相信它回答了原来的问题。
就原始代码而言,我认为将 WidgetHolder 作为 Test 类的成员,然后返回对它的 const 或非 const 引用,并使 Widgets 成为 Holder 的私有成员,并提供一个每个 Widget 的 const 和 none const 访问器。
然后是主课
The original query was how to return the WidgetHolder as const if the containing class was const. C++ uses const as part of the function signature and therefore you can have const and none const versions of the same function. The none const one is called when the instance is none const, and the const one is called when the instance is const. Therefore a solution is to access the widgets in the widget holder by functions, rather than directly. I have create a more simple example below which I believe answers the original question.
In terms of the original code, I think it would be easier to have a WidgetHolder as a member of the class Test and then return either a const or none const reference to it, and make the Widgets private members of the holder, and provide a const and none const accessor for each Widget.
And then on the main class
编辑:他删除了他的答案,让我看起来有点愚蠢:)
Flame 的答案是危险的错误。 他的 WidgetHolder 在构造函数中引用了一个值对象。 一旦构造函数返回,该按值传递的对象将被销毁,因此您将保留对已销毁对象的引用。
使用他的代码的一个非常简单的示例应用程序清楚地表明了这一点:
输出将类似于
为了避免这种情况,WidgetHolder 构造函数应该引用它想要存储为引用的变量。
EDIT: he deleted his answer, making me look a bit foolish :)
The answer by Flame is dangerously wrong. His WidgetHolder takes a reference to a value object in the constructor. As soon as the constructor returns, that passed-by-value object will be destroyed and so you'll hold a reference to a destroyed object.
A very simple sample app using his code clearly shows this:
The output would be something like
To avoid this the WidgetHolder constructor should take references to the variables it wants to store as references.
之所以能够编译,是因为虽然 WidgetHolder 是一个 const 对象,但这种 const 性不会自动应用于指向 WidgetHolder(由其引用)的对象。 从机器级别考虑 - 如果 WidgetHolder 对象本身保存在只读内存中,您仍然可以写入 WidgetHolder 指向的内容。
问题似乎出在这一行:
正如 Frank 提到的,在构造函数返回后,WidgetHolder 类中的引用将保留无效引用。 因此,您应该将其更改为:
这样做后,它将无法编译,我将其作为练习留给读者来解决解决方案的其余部分。
This compiles because although the WidgetHolder is a const object, this const-ness does not automatically apply to objects pointed to (referenced by) the WidgetHolder. Think of it at a machine level - if the WidgetHolder object itself were held in read-only memory, you could still write to things that were pointed to by the WidgetHolder.
The problem appears to lie in this line:
As Frank mentioned, your references inside the WidgetHolder class are going to hold invalid references after the constructor returns. Therefore, you should change this to:
After you do that, it won't compile, and I leave it as an exercise for the reader to work out the rest of the solution.