2013-03-20 34 views
0

我是一名C++程序员,学习C++,遇到了一些麻烦。 我试图将结构类型'Person'的对象推入向量中,但是不会复制属于Person类型成员的字符串值。另外,代码退出一个错误信息 - 张贴在底部:错误将字符串成员的结构对象插入std :: vector

#include <iostream> 
#include <vector> 
#include <string> 
#include <stdio.h> 
#include <string.h> 

using namespace std; 

typedef struct Person { 
    string Name; 
    string Lastname; 
    int Age; 
} Person; 

void CreatePerson(Person* in_person, string in_name, string in_last, 
    int in_age) 
{ 
    Person t_person; 
    t_person.Name = in_name; 
    t_person.Lastname = in_last; 
    t_person.Age = in_age; 

    memcpy(in_person, &t_person, sizeof(t_person)); 
} 

int main(int argc, char *argv[]) 
{ 
    vector<Person> people; 
    Person t_ppl; 

    CreatePerson(&t_ppl, "Zareh", "Petros", 13); 
    people.push_back(t_ppl); 

    CreatePerson(&t_ppl, "Tina", "Yarroos", 26); 
    people.push_back(t_ppl); 

    int ii; 
    for(ii=0; ii < people.size() ; ii++) { 
     cout << "Element - " << ii << endl; 
     cout << "name:" << people[ii].Name << endl; 
     cout << "lastname:" << people[ii].Lastname << endl; 
     cout << "age:" << people[ii].Age << endl; 
    } 

    return 0; 
} 

这里是错误消息:

*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x09d48048 *** 
======= Backtrace: ========= 
/lib/i386-linux-gnu/libc.so.6(+0x75ee2)[0xb74e8ee2] 
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0xb76e551f] 
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSs4_Rep10_M_destroyERKSaIcE+0x1b)[0xb76cc99b] 
/usr/lib/i386-linux-gnu/libstdc++.so.6(+0x909dc)[0xb76cc9dc] 
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSsD1Ev+0x2e)[0xb76cca4e] 
+0

你混合C('memcpy')和C++('STL'),并且是造成混乱。改为使用'std :: copy'。 – iammilind 2013-03-20 05:42:43

回答

2

你已经被你不应该在这种情况下使用memcpy说过,所以我不会打扰重复那。

您的CreatePerson的问题远远超出了使用memcpy,只是更改为std::copy并不是真的会做得对。

取而代之的是自由函数来创建一个人,你几乎可以肯定应该编写的功能构造来代替:

struct Person { 
    string Name; 
    string Lastname; 
    int Age; 

    Person(string Name, string Last, int Age) 
     : Name(Name), LastName(Last), Age(Age) 
    {} 
}; 

有了这个,我们可以创建一个Person对象更干净:

std:::vector<Person> people; 

people.push_back(Person("Zarah", "Petros", 13)); 
people.push_back(Person("Tina", "Yarroos", 26)); 

我还会写一个插件,它负责以正确的格式显示Person

std::ostream &operator<<(std::ostream &os, Person const &p) { 
    return os << "Name: " << p.Name < "\n" 
       << "Last: " << p.LastName << "\n" 
       << "Age: " << p.Age << "\n"; 
} 

有了这个,你对你的代码的主流可以将完整的Person对象为信息流,而不注意一个什么样的Person包含或者它应该如何显示内部细节:

for (int i=0; i<people.size(); i++) 
    std::cout << people[i] << "\n"; 

如果你想成为一个多一点雄心的话,可以使用标准的算法来代替:

std:copy(people.begin(), people.end(), 
     std::ostream_iterator<Person>(std::cout, "\n")); 

或者,如果您使用的是相对较新的编译器,你可以使用基于范围的for循环:

for (auto &p : people) 
    std::cout << p << "\n"; 

把所有一起,整个程序结束了这样的事情:

#include <string> 
#include <iostream> 
#include <vector> 

using std::string; 

struct Person { 
    string Name; 
    string LastName; 
    int Age; 

    Person(string Name, string Last, int Age) 
     : Name(Name), LastName(Last), Age(Age) 
    {} 
}; 

std::ostream &operator<<(std::ostream &os, Person const &p) { 
    return os << "Name: " << p.Name << "\n" 
       << "Last: " << p.LastName << "\n" 
       << "Age: " << p.Age << "\n"; 
} 

int main(){ 
    std::vector<Person> people; 

    people.push_back(Person("Zarah", "Petros", 13)); 
    people.push_back(Person("Tina", "Yarroos", 26)); 

    for (auto &p : people) 
     std::cout << p << "\n"; 
    return 0; 
} 
+0

非常感谢你。我需要阅读一本正确的C++书籍,其中讨论了哪些C代码不能使用。 – ArmenB 2013-03-20 06:39:20

+0

@ArmenB .: *加速C++ *。它并没有真正谈论什么C代码不使用,但它教会C++应该使用它的方式(C++书籍中一个非常罕见的特性)。 – 2013-03-20 06:40:41

2

不要对非POD类型使用memcpy()。它不调用复制构造函数。

改为使用std::copy()

在这种情况下,分配更容易。替换:

memcpy(in_person, &t_person, sizeof(t_person)); 

*in_person = t_person; 
+0

当t_person存在函数时,t_person是否会从堆栈中被调用,然后* in_person将是空的? – ArmenB 2013-03-20 06:42:00

+1

不,它不会。副本正在制作中。所以即使't_person'超出了范围,'* in_person'仍然是有效的,因为它是一个副本。 – Kyurem 2013-03-20 06:45:28

3

的std :: string是一个类,不应由一个memcpy的操作进行复制。它可能持有特定于实例的数据,如果由两个不同的实例持有(并且可能是您的问题的原因),则该数据将被混淆。

试想一下,那的std :: string是一样的东西:

class string 
{ 
private: 
    char * data; 
    int dataLength; 
}; 

如果memcpy的一个串到另一个,数据和数据长度被复制到另一个地方(最近被当作一个正常的字符串实例)。但是,如果在这些字符串上调用析构函数(当它们超出范围时),它们将尝试释放保存在data字段中的数据。第一个字符串(它是这个指针的实际所有者)将释放指针指向的内存。但是,然后复制的字符串的另一个析构函数将会运行,并会尝试再次释放此内存,这是不允许的。

请注意,这正是您的系统正在报告的内容:双重释放内存。

你的代码非常C风格。在C++中,可以用构造函数创建一个类,而不是一个填充结构的函数。我会用以下方式编写代码:

#include <iostream> 
#include <vector> 
#include <string> 
#include <stdio.h> 
#include <string.h> 

using namespace std; 

struct Person 
{ 
public: 
    string Name; 
    string Lastname; 
    int Age; 

    Person(string newName, string newLastname, int newAge) 
     : Name(newName), Lastname(newLastname), Age(newAge) 
    { 

    } 
}; 

int main(int argc, char *argv[]) 
{ 
    vector<Person> people; 

    Person person1("Zareh", "Petros", 13); 
    people.push_back(person1); 

    Person person2("Tina", "Yarros", 26); 
    people.push_back(person2); 

    for(unsigned int i=0; i < people.size() ; i++) 
    { 
     cout << "Element - " << i << endl; 
     cout << "name:" << people[i].Name << endl; 
     cout << "lastname:" << people[i].Lastname << endl; 
     cout << "age:" << people[i].Age << endl; 
    } 

    getchar(); 

    return 0; 
} 

创建方法的角色需要类构造函数。它正确地填写了课程的各个领域。此外,C++提供了默认的复制构造函数和赋值运算符,它将处理将一个人正确分配给另一个人。


关于你的代码风格的一些附注。

  • 在C++中避免使用memcpy。如果你需要使用它,你可能应该考虑创建适当的拷贝构造函数,std :: copy或者只是做一个任务(在你的情况下完美的工作)。 memcpy应该使用只有复制原始块的内存。
  • typedef不再需要C++中的结构体。而是写:

    typedef struct Name { ... } Name; 
    

    你可以简单的写:

    struct Name { ... }; 
    
+0

非常感谢 - 我觉得我需要适当的C++教育。 – ArmenB 2013-03-20 06:44:37

相关问题