【问题标题】:Are structure members of structure passed by reference, passed ONLY by value?结构的结构成员是否通过引用传递,仅通过值传递?
【发布时间】:2013-05-22 11:33:24
【问题描述】:

我的模块尝试按照以下程序进行操作:子函数尝试修改结构的元素并将其返回给通过引用传递结构的函数。

#include <iostream>
#include <vector>
using namespace std;

struct a
{
  int val1;
  vector<int> vec1;
};

struct a* foo();

void anotherfunc(struct a &input);

int main()
{
  struct a *foo_out;
  foo_out = foo();
  cout<< "Foo out int val: "<< foo_out->val1<<"\n";
  cout<< "Foo out vector size: "<< foo_out->vec1.size()<< "\n";

  cout<< "Foo out vector value1: "<< foo_out->vec1.at(0)<< "\n";
  cout<< "Foo out vector value2: "<< foo_out->vec1.at(1)<< "\n";
  return 0;
}


struct a *foo()
{
  struct a input;
  input.val1=729;
  anotherfunc(input);  
  return &input;
}

void anotherfunc(struct a &input)
{
  input.vec1.push_back(100);
  input.vec1.push_back(1000);
  input.vec1.push_back(1024);
  input.vec1.push_back(3452);

  cout<< "Anotherfunc():input vector value1: "<< input.vec1.at(0)<< "\n";
  cout<< "Anotherfunc():input vector value2: "<< input.vec1.at(1)<< "\n";
  cout<< "Anotherfunc():input int val: "<< input.val1<< "\n";

}

我希望 main 函数在结构 (729) 中包含修改后的整数值,以及向量值 (100,10000,1024 和 3452)。相反,main 没有这些值,并且在 g++ 上,程序显示出一种奇怪的行为:main() 显示结构体内部的向量中有 4 个元素,但是在尝试打印值时,出现段错误。

经过深思熟虑,我认为我的问题是:“结构的结构成员是否通过引用传递,仅通过值传递?”我不应该期望该向量具有由通过引用传递整个结构的函数设置的值吗?请帮忙。

维杰

【问题讨论】:

  • 您似乎将“结构”视为仍在编写 C。停止到处写 structa 本身就是一个类型。

标签: c++


【解决方案1】:
struct a *foo()
{
  struct a input;
  input.val1=729;
  anotherfunc(input);  
  return &input;
}

您正在返回本地对象上的指针(它将在退出函数时被销毁),因此,这里有悬空指针并且您的程序具有未定义的行为。

【讨论】:

    【解决方案2】:

    正如 ForeEveR 所说,您返回的指针指向不再保证包含有效对象的内存。如果您想要这种行为,请在堆上分配input,如下所示:

    a * foo ()
    {
        a * input = new input;
        input->val1 = 729;
        anotherfunc (*input);
        return input;
    }
    

    现在调用foo的人有责任释放这个内存,例如

    {
        a * foo_out = foo();
        // do stuff with foo_out
        delete foo_out; foo_out = 0;
    }
    

    在某些时候你会意识到跟踪谁分配了哪些对象是乏味的,当这种情况发生时你应该查找“智能指针”。

    【讨论】:

    • 或者更好的是,返回一个值并避免所有这些对动态内存的影响。
    • 我不想开始讨论过早的优化等;从他的帖子看来,他正在学习指针和引用,所以我坚持这样做。
    • 无论列表多么大,现代编译器都会通过移动而不是复制来返回它,并且任何体面的编译器都会忽略移动/复制。结果将(几乎可以肯定)比额外的动态分配更有效。
    • 我不是在谈论优化(过早或其他),而是关于便利性。通过返回一个对象,调用者不需要处理它的生命周期。它也更有效率的可能性只是一个奖励。
    【解决方案3】:

    首先,C++ 中的“结构”并没有什么特别神奇的地方——你应该像对待任何其他类型一样对待它们。特别是,你不需要到处写关键字struct

    因此,这是您使用更惯用的 C++ 编写的代码(也重新排序以避免那些浪费的预先声明):

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct a
    {
       int val1;
       vector<int> vec1;
    };
    
    void bar(a& input)
    {
       input.vec1.push_back(100);
       input.vec1.push_back(1000);
       input.vec1.push_back(1024);
       input.vec1.push_back(3452);
    
       cout << "bar():input vector value1: " << input.vec1.at(0) << "\n";
       cout << "bar():input vector value2: " << input.vec1.at(1) << "\n";
       cout << "bar():input int val: "       << input.val1       << "\n";
    }
    
    a* foo()
    {
      a input;
      input.val1=729;
      bar(input);  
      return &input;
    }
    
    int main()
    {
       a* foo_out = foo();
       cout << "Foo out int val: "       << foo_out->val1        << "\n";
       cout << "Foo out vector size: "   << foo_out->vec1.size() << "\n";
    
       cout << "Foo out vector value1: " << foo_out->vec1.at(0)  << "\n";
       cout << "Foo out vector value2: " << foo_out->vec1.at(1)  << "\n";
    }
    

    现在,正如其他人指出的那样,foo() 被破坏了,因为它返回了一个指向本地对象的指针。

    为什么所有的指针诡计?如果您担心复制该向量,那么您可以动态分配 a 对象并使用 共享指针 实现来为您管理该内存:

    void bar(shared_ptr<a> input)
    {
       input->vec1.push_back(100);
       input->vec1.push_back(1000);
       input->vec1.push_back(1024);
       input->vec1.push_back(3452);
    
       cout << "bar():input vector value1: " << input->vec1.at(0) << "\n";
       cout << "bar():input vector value2: " << input->vec1.at(1) << "\n";
       cout << "bar():input int val: "       << input->val1       << "\n";
    }
    
    shared_ptr<a> foo()
    {
      shared_ptr<a> input(new a);
      input->val1 = 729;
      bar(input);
      return input;
    }
    

    否则,只需按值传递即可。

    【讨论】:

      猜你喜欢
      • 2013-06-04
      • 2013-05-12
      • 2011-02-02
      • 1970-01-01
      • 1970-01-01
      • 2015-11-14
      • 2014-12-13
      • 1970-01-01
      相关资源
      最近更新 更多