我正在上一门有几年历史的课程,所以第一次学习如何使用序列化。
当“返回结果”在lambda中执行时,联系人的Address属性将未初始化。注释掉的代码工作得很好,所以我非常肯定,我编译了Boost库,ok。
联系人上的名字还好。为什么地址没有?
#include <string>
#include <iostream>
#include <memory>
#include <functional>
#include <sstream>
using namespace std;
#include <boost/serialization/serialization.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
struct Address
{
public:
string street, city;
int suite;
Address() {};
Address(string street, string city, int suite)
: suite(suite),street(street),city(city){ }
friend ostream& operator<<(ostream& os, const Address& obj)
{
return os
<< "street: " << obj.street
<< " city: " << obj.city
<< " suite: " << obj.suite;
}
private:
friend class boost::serialization::access;
template<class Ar> void serialize(Ar& ar, const unsigned int version)
{
ar & street;
ar & city;
ar & suite;
}
};
struct Contact
{
string name;
Address* address;
friend ostream& operator<<(ostream& os, const Contact& obj)
{
return os
<< "name: " << obj.name
<< " address: " << *obj.address;
}
private:
friend class boost::serialization::access;
template<class Ar> void serialize(Ar& ar, const unsigned int version)
{
ar & name;
ar & address;
}
};
int main()
{
Contact john;
john.name = "John Doe";
john.address = new Address{ "123 East Dr", "London", 123 };
auto clone = [](Contact c)
{
ostringstream oss;
boost::archive::text_oarchive oa(oss);
oa << c;
string s = oss.str();
Contact result;
istringstream iss(s);
boost::archive::text_iarchive ia(iss);
ia >> result;
return result;
};
// This works fine
//ostringstream oss;
//boost::archive::text_oarchive oa(oss);
//oa << john;
//string s = oss.str();
//Contact newJane;
//{
// istringstream iss(s);
// boost::archive::text_iarchive ia(iss);
// ia >> newJane;
//}
//newJane.name = "Jane";
//newJane.address->street = "123B West Dr";
//cout << john << endl << newJane << endl;
Contact jane = clone(john);
jane.name = "Jane";
jane.address->street = "123B West Dr";
cout << john << endl << jane << endl;
getchar();
return 0;
}发布于 2018-09-28 06:22:59
Contact不会重载复制构造函数。因此,将生成缺省值。
默认复制构造函数使用其默认构造函数复制所有(非static)成员变量。具体来说,指针的默认构造函数只复制存储的地址。
因此,使用Contact的复制构造,将构造一个新实例,其中Contact::address指向与原始实例完全相同的Address。
因此,改变jane的地址也会改变joe的地址。
这可能是有意的,也可能不是:
Contact拥有其address的独家所有权。如果jane和joe没有结婚,这可能是意料之外的。
在目前的状态下,该设计还有另一个缺陷:
当一个address被销毁时,哪个实例负责删除Contact点?
如果将其添加到析构函数~Contact()中,情况就会变得更糟。(Deleteing jane会删除她的地址,并给john留下一个悬空指针。)
就像现在一样,破坏Contact可能会导致内存泄漏。(外部代码必须负责删除Address的左边实例。这是很难维持的。
这样的设计问题并不罕见,并导致了Rule of three,它说:
如果其中之一
是显式定义的,那么另一个也很可能也定义了。
使用C++11 (引入移动语义),将其扩展到五个添加的规则
因此,一个明确的定义可以是简单地删除它们:
struct Contact {
Address *address;
// default constructor with initialization to empty
Contact(): address(new Address()) { }
// constructor with values
Contact(const Address &address): address(new Address(address)) { }
// destructor.
~Contact()
{
delete address; // prevent memory leak
}
// move constructor.
Contact(Contact &&contact): address(contact.address)
{
contact.address = nullptr; // prevent two owners
}
// move assignment.
Contact& operator=(Contact &&contact)
{
address = contact.address;
contact.address = nullptr; // prevent two owners
return *this;
}
// prohibited:
Contact(const Contact&) = delete;
Contact& operator=(const Contact&) = delete;
};这是内存管理方面的一个改进,但对于clone()实例Contact的意图却适得其反。
另一个可能的解决方案是将address存储为std::shared_ptr<Address>而不是Address*。针对这类问题(涉及共享所有权),引入了std::shared_ptr (智能指针之一)。
struct Contact {
std::shared_ptr<Address> address;
// default constructor with initialization to empty
Contact(): address(std::make_shared<Address>()) { }
// constructor with values
Contact(const Address &address):
address(std::make_shared<Address>(address))
{ }
// another constructor with values
Contact(const std::shared_ptr<Address> &address):
address(address)
{ }
// destructor.
~Contact() = default;
/* default destructor of shared_ptr is fully sufficient
* It deletes the pointee just if there are no other shared_ptr's to it.
*/
// copy constructor.
Contact(const Contact&) = default; // copies shared_ptr by default
// copy assignment.
Contact& operator=(const Contact&) = default; // copies shared_ptr by default
// move constructor.
Contact(Contact&&) = default;
// move assignment.
Contact& operator=(Contact&&) = default;
};在这种情况下,将“5”设置为默认值实际上就像将它们排除在外一样。
我在检查不写任何愚蠢的东西时发现的链接:
发布于 2018-09-28 09:10:13
没有令人信服的理由在Address中使用指向Contact的指针,所以不要使用,这也意味着编译器生成的复制构造函数可以替换clone。
struct Contact
{
string name;
Address address;
friend ostream& operator<<(ostream& os, const Contact& obj)
{
return os
<< "name: " << obj.name
<< " address: " << obj.address;
}
private:
friend class boost::serialization::access;
template<class Ar> void serialize(Ar& ar, const unsigned int version)
{
ar & name;
ar & address;
}
};
int main()
{
Contact john;
john.name = "John Doe";
john.address = Address{ "123 East Dr", "London", 123 };
Contact jane = john;
jane.name = "Jane";
jane.address.street = "123B West Dr";
cout << john << endl << jane << endl;
getchar();
return 0;
}https://stackoverflow.com/questions/52546765
复制相似问题