构造结构&

发布于 2024-07-06 04:28:28 字数 1225 浏览 8 评论 0原文

我在弄清楚 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

自由范儿 2024-07-13 04:28:28

您的 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.

刘备忘录 2024-07-13 04:28:28

您需要创建一个专门用于保存 const Widget& 的新类型。 对象。 即:


struct ConstWidgetHolder
{
    ConstWidgetHolder(const Widget &a, const Widget &b, const Widget &c, const Widget &d): A(a), B(b), C(c), D(d){}

    const Widget& A;
    const Widget& B;
    const Widget& C;
    const Widget& D;
};

class Test
{
public:
    ConstWidgetHolder AccessWidgets() const
    {
        return ConstWidgetHolder(A, B, C, D);
    }

您现在将收到以下错误(在 gcc 4.3 中):

widget.cc: In function 'int main()':
widget.cc:51: error: assignment of data-member 'Widget::x' in read-only structure

在带有迭代器的标准库中使用了类似的习惯用法,即:


class vector {
    iterator begin();
    const_iterator begin() const;

You need to create a new type specifically for holding const Widget& objects. Ie:


struct ConstWidgetHolder
{
    ConstWidgetHolder(const Widget &a, const Widget &b, const Widget &c, const Widget &d): A(a), B(b), C(c), D(d){}

    const Widget& A;
    const Widget& B;
    const Widget& C;
    const Widget& D;
};

class Test
{
public:
    ConstWidgetHolder AccessWidgets() const
    {
        return ConstWidgetHolder(A, B, C, D);
    }

You will now get the following error (in gcc 4.3):

widget.cc: In function 'int main()':
widget.cc:51: error: assignment of data-member 'Widget::x' in read-only structure

A similar idiom is used in the standard library with iterators ie:


class vector {
    iterator begin();
    const_iterator begin() const;

糖粟与秋泊 2024-07-13 04:28:28

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.

醉酒的小男人 2024-07-13 04:28:28

最初的查询是如果包含的类是 const,如何将 WidgetHolder 作为 const 返回。 C++ 使用 const 作为函数签名的一部分,因此同一函数可以有 const 版本和非 const 版本。 当实例不是const时,调用none const;当实例是const时,调用const。 因此,解决方案是通过函数而不是直接访问小部件持有者中的小部件。 我在下面创建了一个更简单的示例,我相信它回答了原来的问题。

#include <stdio.h>

class Test
{
public:
  Test(int v){m_v = v;}
 ~Test(){printf("Destruct value = %d\n",m_v);}

 int& GetV(){printf ("None Const returning %d\n",m_v); return m_v;  }

 const int& GetV() const { printf("Const returning %d\n",m_v); return m_v;}
private:
  int m_v;
};

void main()
{
  // A none const object (or reference) calls the none const functions
  // in preference to the const
  Test one(10);
  int& x = one.GetV();
  // We can change the member variable via the reference
  x = 12;

  const Test two(20);
  // This will call the const version  
  two.GetV();

  // So the below line will not compile
  // int& xx = two.GetV();

  // Where as this will compile
  const int& xx = two.GetV();

  // And then the below line will not compile
  // xx = 3;

}

就原始代码而言,我认为将 WidgetHolder 作为 Test 类的成员,然后返回对它的 const 或非 const 引用,并使 Widgets 成为 Holder 的私有成员,并提供一个每个 Widget 的 const 和 none const 访问器。

class WidgetHolder {
...

Widget& GetA();
const Widget& GetA() const;
...
};

然后是主课

class Test {
...
WigetHolder& AccessWidgets() { return m_Widgets;}
const WidgetHolder&AcessWidgets() const { return m_Widgets;}

private:
  WidgetHolder m_Widgets;
...
};

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.

#include <stdio.h>

class Test
{
public:
  Test(int v){m_v = v;}
 ~Test(){printf("Destruct value = %d\n",m_v);}

 int& GetV(){printf ("None Const returning %d\n",m_v); return m_v;  }

 const int& GetV() const { printf("Const returning %d\n",m_v); return m_v;}
private:
  int m_v;
};

void main()
{
  // A none const object (or reference) calls the none const functions
  // in preference to the const
  Test one(10);
  int& x = one.GetV();
  // We can change the member variable via the reference
  x = 12;

  const Test two(20);
  // This will call the const version  
  two.GetV();

  // So the below line will not compile
  // int& xx = two.GetV();

  // Where as this will compile
  const int& xx = two.GetV();

  // And then the below line will not compile
  // xx = 3;

}

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.

class WidgetHolder {
...

Widget& GetA();
const Widget& GetA() const;
...
};

And then on the main class

class Test {
...
WigetHolder& AccessWidgets() { return m_Widgets;}
const WidgetHolder&AcessWidgets() const { return m_Widgets;}

private:
  WidgetHolder m_Widgets;
...
};
心清如水 2024-07-13 04:28:28

编辑:他删除了他的答案,让我看起来有点愚蠢:)

Flame 的答案是危险的错误。 他的 WidgetHolder 在构造函数中引用了一个值对象。 一旦构造函数返回,该按值传递的对象将被销毁,因此您将保留对已销毁对象的引用。

使用他的代码的一个非常简单的示例应用程序清楚地表明了这一点:

#include <iostream>

class Widget
{
    int x;
public:
    Widget(int inX) : x(inX){}
    ~Widget() {
    std::cout << "widget " << static_cast< void*>(this) << " destroyed" << std::endl;
     }
};

struct WidgetHolder
{
    Widget& A;

public:
    WidgetHolder(Widget a): A(a) {}

    const Widget& a() const {
    std::cout << "widget " << static_cast< void*>(&A) << " used" << std::endl;
    return A;
}

};

int main(char** argv, int argc)
{
Widget test(7);
WidgetHolder  holder(test);
Widget const & test2 = holder.a();

return 0;
} 

输出将类似于

widget 0xbffff7f8 destroyed
widget 0xbffff7f8 used
widget 0xbffff7f4 destroyed

为了避免这种情况,WidgetHolder 构造函数应该引用它想要存储为引用的变量。

struct WidgetHolder
{
    Widget& A;

public:
    WidgetHolder(Widget & a): A(a) {}

  /* ... */

};

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:

#include <iostream>

class Widget
{
    int x;
public:
    Widget(int inX) : x(inX){}
    ~Widget() {
    std::cout << "widget " << static_cast< void*>(this) << " destroyed" << std::endl;
     }
};

struct WidgetHolder
{
    Widget& A;

public:
    WidgetHolder(Widget a): A(a) {}

    const Widget& a() const {
    std::cout << "widget " << static_cast< void*>(&A) << " used" << std::endl;
    return A;
}

};

int main(char** argv, int argc)
{
Widget test(7);
WidgetHolder  holder(test);
Widget const & test2 = holder.a();

return 0;
} 

The output would be something like

widget 0xbffff7f8 destroyed
widget 0xbffff7f8 used
widget 0xbffff7f4 destroyed

To avoid this the WidgetHolder constructor should take references to the variables it wants to store as references.

struct WidgetHolder
{
    Widget& A;

public:
    WidgetHolder(Widget & a): A(a) {}

  /* ... */

};
童话里做英雄 2024-07-13 04:28:28

之所以能够编译,是因为虽然 WidgetHolder 是一个 const 对象,但这种 const 性不会自动应用于指向 WidgetHolder(由其引用)的对象。 从机器级别考虑 - 如果 WidgetHolder 对象本身保存在只读内存中,您仍然可以写入 WidgetHolder 指向的内容。

问题似乎出在这一行:

WidgetHolder(Widget a, Widget b, Widget c, Widget d): A(a), B(b), C(c), D(d){}

正如 Frank 提到的,在构造函数返回后,WidgetHolder 类中的引用将保留无效引用。 因此,您应该将其更改为:

WidgetHolder(Widget &a, Widget &b, Widget &c, Widget &d): A(a), B(b), C(c), D(d){}

这样做后,它将无法编译,我将其作为练习留给读者来解决解决方案的其余部分。

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:

WidgetHolder(Widget a, Widget b, Widget c, Widget d): A(a), B(b), C(c), D(d){}

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:

WidgetHolder(Widget &a, Widget &b, Widget &c, Widget &d): A(a), B(b), C(c), D(d){}

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文