【问题标题】:Struct is "reset"结构是“重置”
【发布时间】:2011-11-11 14:17:43
【问题描述】:

我无法理解以下代码的输出:

int main(void)
{
    vector<TreeNode> tree;
    for(int i = 0; i < 50; i++)
    {
        TreeNode node;
        tree.push_back(node);
    }

    for(int i = 0; i < 50; i++)
    {
        Image image;
        image.Path = "TestPath";
        image.Votes = 0;

        TreeNode node = tree.at(i);
        node.images.push_back(image);
        node.images.push_back(image);
    }

    TreeNode node = tree.at(0);
    cout << "TEST" << endl;
    cout << node.images.size() << endl;
}

输出:

TEST
0

为什么输出为 0,我应该怎么做才能修复它?我希望大小为 2 而不是 0。 它可能与结构的工作方式有关。我定义的两个结构如下:

typedef struct
{
    string Path;
    int Votes;
} Image;

typedef struct
{
    int treeIndex;
    float centroid;
    vector<float*> features;
    vector<Image> images;
} TreeNode;

请注意,我不能选择使用类而不是结构。

【问题讨论】:

  • 请注意,除了默认可见性(public/private)之外,结构和类是相同的。
  • 通过副本传递与通过引用传递之美...顺便说一句,您的整个开头段落可以缩短为vector&lt;TreeNode&gt; tree(50);。还有,这个怎么标为C??
  • 为什么是 typedef?那是过时的旧 C 风格
  • (并且推回同一事物的重复副本可以缩短为v.insert(v.end(), 2, image);。)程序员讨厌重复:-)
  • 没有“返回”。东西是“输出”。函数返回。

标签: c++ vector struct


【解决方案1】:

vector::at 返回一个对象的引用。

你的线路

TreeNode node = tree.at(i);

正在节点中创建 TreeNode 的副本,因此当您向其中添加图像时,它会将它们添加到不在您的向量中的新对象。

如果你改为使用

TreeNode& node = tree.at(i);

它将正确添加图像。

【讨论】:

  • 谢谢大家!正是我需要的:)
【解决方案2】:

您正在按值检索节点,并修改您的本地副本。试试

TreeNode &node = tree.at(i);

【讨论】:

    【解决方案3】:

    你的问题出在这一行:

    TreeNode node = tree.at(i);
    

    在这里,您正在制作存储在容器中的节点的副本。您的后续代码会修改该副本,而不是原始代码。最后,您从未修改的容器中访问原始内容。

    改为使用

    TreeNode& node = tree.at(i);
    

    使node 引用存储在向量中的对象。 &amp; 表示节点号不是TreeNode 对象,而是对TreeNode 对象的引用。也就是说,对node的每次访问实际上都会访问它所绑定的对象,即tree.at(i)返回的对象。

    顺便说一句,您的代码还有其他需要注意的地方。

    首先,你说你不能使用类,但必须使用结构。在 C++ 中,struct 和 class 完全一样,只是 struct 默认情况下所有成员都是 public。即以下两个代码示例是完全等价的:

    struct X
    {
      int i;
      int k;
    };
    

    class X
    {
    public:
      int i;
      int k;
    };
    

    实际上,您甚至可以使用 struct 前向声明您的类型,然后使用 class 定义它,反之亦然。

    需要使用 struct 而不是 class 可能仅意味着以下两件事之一:要么您需要在 C 中也包含文件(不知道 class 关键字),但在您的情况下,您无论如何都做不到,因为 C 既不知道向量也不知道字符串。或者您需要让您的类成为 POD(普通旧数据)类型,但同样,您的结构不是 POD 类型,因为它们具有非 POD 类型 stringvector&lt;T&gt; 的成员。换句话说,你的结构已经是类,在任何意义上。

    在相关节点中,由于无法在 C 中包含结构的定义,因此在此处使用 typedef 是没有意义的。在 C++ 中,

    struct Image
    {
      string Path;
      int Votes;
    };
    

    已经允许您使用 Image 来引用类型(不像在 C 中您需要使用 struct Image 来引用这种情况下的类型)。

    【讨论】:

    • 我需要将它与 CUDA 一起使用。 CUDA 同时支持 C 和 C++,但对我来说,它只在我使用 C 语法时才有效。这就是为什么:)
    【解决方案4】:
    TreeNode node = tree.at(i);
    

    您正在获取节点的副本并修改副本,而原始保持不变。

    【讨论】:

      【解决方案5】:
      TreeNode node = tree.at(i);
      node.images.push_back(image);
      node.images.push_back(image);
      

      在这里,您在索引i 处获取了TreeNode副本,并向其中添加了一些内容。然后副本在离开作用域时立即被销毁。

      取而代之的是,获取一个引用,以便您处理容器中的原始对象:

      TreeNode& node = tree.at(i);
      node.images.push_back(image);
      node.images.push_back(image);
      

      【讨论】:

        【解决方案6】:

        为什么要先插入节点,然后再修改向量中的节点?正确构造(完成修改)节点后,您可以插入节点。您根本不需要第一个循环,只需将推送放在第二个循环的末尾

        【讨论】:

        • 这只是一个简单的例子来描述我的问题:)
        猜你喜欢
        • 2014-01-22
        • 2021-06-02
        • 2018-11-27
        • 2016-05-13
        • 1970-01-01
        • 2016-03-29
        • 2018-10-23
        • 1970-01-01
        • 2018-06-01
        相关资源
        最近更新 更多