函数返回结构矢量的副本

时间:2014-05-15 07:17:44

标签: c++ stl

我在Visual Studio 2010中这样做。

我调用返回结构向量的函数。然后我将第一个向量元素(一个结构)存储到本地结构中,然后访问该结构的字符串成员,我得到正确的值。

但是如果我通过应用方括号访问相同的字符串值,直接到函数调用本身,我得到垃圾结果。

struct stNameAge
{
    char Name[64];
    int Age;
};

typedef std::vector<stNameAge> NamesAndAges;

NamesAndAges GetNamesAndAges()
{
    stNameAge nameage;
    strcpy_s (nameage.Name, 64, "My name goes here"); 
    nameage.Age = 23; 

    NamesAndAges nameandages;
    nameandages.push_back(nameage);

    return nameandages;
}

int _tmain(int argc, _TCHAR* argv[])
{
    stNameAge nameage = GetNamesAndAges()[0];

    char* MyName1 = nameage.Name ; // I get correct value of name here
    int MyAge1 = nameage.Age ;    // I get correct value here

    char* MyName2 = GetNamesAndAges()[0].Name ; // *** I get garbage value here ***
    int MyAge2 = GetNamesAndAges()[0].Age ; // I get correct value here

    return 0;
}

我在这里真的很无能为力。有人可以解释为什么会这样吗?

已编辑: (已添加以下新代码)

如果我保持矢量全局,那么它仍然是相同的情况。我相信返回的矢量本身并不是一个好主意。

struct stNameAge
{
    char Name[256];
    int Age;
};

typedef std::vector<stNameAge> NamesAndAges;

NamesAndAges nameandages;

NamesAndAges GetNamesAndAges()
{
    stNameAge nameage;
    strcpy_s (nameage.Name, 64, "My name goes here"); 
    nameage.Age = 23; 

    nameandages.push_back(nameage);

    return nameandages;
}

int _tmain(int argc, _TCHAR* argv[])
{
    // Function returning vector of structs 
    stNameAge nameage = GetNamesAndAges()[0];

    char* MyName2 = GetNamesAndAges()[0].Name ; // *** I get garbage value here ***

    char* MyName1 = nameage.Name ; // I get correct value of name here

    return 0;
}

2 个答案:

答案 0 :(得分:5)

两者之间存在细微差别,在第一种情况下,您将有效值复制到另一个有效变量,而在第二种情况下,无法保存&#34;结果&# 34。

在第一次出现时,您使用堆栈上的临时值来创建向量,然后您将其返回并复制 - 将值分配给您可以安全使用的另一个变量

stNameAge nameage = GetNamesAndAges()[0];

在第二步中你要创建一个临时向量,请求一个元素,但要求指向该元素的指针。当向量被破坏时,指针不再有效

char* MyName2 = GetNamesAndAges()[0].Name ;

你能看出两种情况之间的区别吗?

在伪代码中,我们可以用以下内容进行总结

int nameage;
int *pointer;
{
  int value = 44; // The value you're interested in

  nameage = value; // You can safely use nameage from this point forward
  pointer = &value; // When the scope ends, there's no guarantee you'll be pointing to valid data
}

// nameage is valid here, pointer is likely not and even if it is it's undefined behavior

答案 1 :(得分:3)

当你这样写:

stNameAge nameage = GetNamesAndAges()[0];

返回的对象(因为它是函数的本地对象)被销毁,但在销毁之前,第一个对象(来自向量)被复制nameage变量。这就是它运作的原因。

然而,当你写:

char* MyName2 = GetNamesAndAges()[0].Name;

这里,由于Name是一个指针,它仍然指向不再属于该程序的同一地址(因为返回的对象被销毁)。所以MyName2指向被破坏的对象。

int MyAge2 = GetNamesAndAges()[0].Age ;

与第一名相同。该对象是复制

在所有情况下,都会发生 copy 。那么为什么第二个不起作用,而是第一个和第三个工作?好吧,因为当指针被复制时,它仍然指向同一个对象 - 指针所指向的对象不被复制,所以在第二种情况下,对象(由指针指向) )被销毁,但复制指针仍然指向它。