我是C#,C程序员学习C ++,我遇到了一些麻烦。 我正在尝试将结构类型“Person”的对象推送到向量中,但不会复制作为Person类型成员的字符串值。此外,代码退出并显示错误消息 - 发布在底部:
#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 :(得分:3)
std :: string是一个类,不应该通过memcpy操作进行复制。它可能包含特定于实例的数据,如果由两个不同的实例持有,这些数据将被加扰(这可能是导致问题的原因)。
想象一下,std :: string类似于:
class string
{
private:
char * data;
int dataLength;
};
如果你将一个字符串memcpy到另一个字符串,data和dataLength都会被复制到另一个地方(最近被视为普通的字符串实例)。但是,当在这些字符串上调用析构函数时(当它们超出范围时),它们将尝试释放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 ++提供了默认的复制构造函数和赋值运算符,它将处理一个人正确分配给另一个人。
关于代码风格的一些注意事项。
memcpy
。如果您需要使用它,您可能应该考虑创建正确的复制构造函数,std :: copy或简单地进行赋值(在您的情况下哪些方法可以完美地工作)。复制原始内存块时,memcpy
应仅用 。C ++中的结构不再需要typedef。而不是写:
typedef struct Name { ... } Name;
您可以简单地写一下:
struct Name { ... };
答案 1 :(得分:2)
不要在非POD类型上使用memcpy()
。它不会调用copy-constructors。
改为使用std::copy()
。
在这种情况下,更容易进行分配。替换:
memcpy(in_person, &t_person, sizeof(t_person));
与
*in_person = t_person;
答案 2 :(得分: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;
}