我对对象引用有点困惑。请查看以下示例:
class ListHandler {
public:
ListHandler(vector<int> &list);
private:
vector<int> list;
}
ListHandler::ListHandler(vector<int> &list) {
this->list = list;
}
由于内部
vector<int> list;
定义,这里我会浪费记忆吗?所以正确的是:
class ListHandler {
public:
ListHandler(vector<int>* list);
private:
vector<int>* list;
}
ListHandler::ListHandler(vector<int>* list) {
this->list = list;
}
ListHandler::~ListHandler() {
delete list;
}
基本上我只想创建一个向量并传递给ListHandler。这个向量不会在ListHandler本身以外的任何地方使用,所以我期待ListHandler做所有其他的事情和清理等等。
答案 0 :(得分:1)
第一个例子不一定是浪费记忆,它只是在“this-&gt; list = list;”中制作整个矢量的副本。 line(可能是你想要的,取决于上下文)。这是因为vector上的operator =方法在那个点上被调用,vector对于它自己及其所有内容的完整副本。
第二个例子绝对不是复制矢量,只是分配一个存储器地址。虽然ListHandler构造函数的调用者更好地意识到ListHandler正在接管指针的控制,因为它最终将最终释放内存。
答案 1 :(得分:1)
这取决于调用者是否希望继续使用他们的列表(在这种情况下你最好不要删除它,并且需要担心它会在你最不期望的时候改变),以及调用者是否要破坏它(在这种情况下)你最好不要指向它。)
如果您的类的文档是调用者使用new分配一个列表,然后在调用构造函数时将所有权转换为您的类,那么保持指针没问题(但是使用auto_ptr以便您不必编写“删除列表“你自己,担心异常安全。”
答案 2 :(得分:1)
这取决于您是否要共享底层矢量。总的来说,我认为尽可能避免共享是一种好习惯,因为它消除了对象所有权的问题。没有分享:
class ListHandler { public: ListHandler(const std::vector<int>& list) : _list(list) {} ~ListHandler(){} private: std::vector<int> _list; };
请注意,与您的示例不同,我将其设为const
,因为原始版本不会被修改。但是,如果我们想要继续并共享相同的底层对象,那么我们可以使用这样的东西:
class ListHandler { public: ListHandler(std::vector<int>& list) : _list(&list) {} ~ListHandler(){} private: std::vector<int>* _list; };
请注意,在这种情况下,我选择将调用者保留为对象的所有者(因此调用者的责任是确保列表在列表处理程序对象的生命周期中存在,并且该列表稍后被释放)。您接管所有权的示例也是可能的:
class ListHandler { public: ListHandler(std::vector<int>* list) : _list(list) {} ListHandler(const ListHandler& o) : _list(new std::vector<int>(o._list)) {} ~ListHandler(){ delete _list; _list=0; } ListHandler& swap(ListHandler& o){ std::swap(_list,o._list); return *this; } ListHandler& operator=(const ListHandler& o){ ListHandler cpy(o); return swap(cpy); } private: std::vector<int>* _list; };
虽然上面肯定是可能的,但我个人并不喜欢它......我发现一个对象不仅仅是一个智能指针类来获取指向另一个对象的指针的所有权而感到困惑。如果我这样做,我会通过将std :: vector包装在智能指针容器中来使其更明确,如下所示:
class ListHandler { public: ListHandler(const boost::shared_ptr< std::vector<int> >& list) : _list(list) {} ~ListHandler(){} private: boost::shared_ptr< std::vector<int> > _list; };
我发现上述内容更清楚地传达了所有权。但是,所有这些不同的传递方式都是可以接受的......只要确保用户知道谁将拥有什么。
答案 3 :(得分:1)
这完全取决于您的需求,以及您可以确保的政策。您的第一个示例没有“错误”(尽管我会通过选择不同的名称来避免明确使用this->
)。它制作了矢量的副本,这可能是正确的做法。这可能是最安全的事情。
但看起来你想要重复使用相同的向量。如果保证列表比任何ListHandler更长,则可以使用引用而不是指针。诀窍是必须在构造函数的初始化列表中初始化引用成员变量,如下所示:
class ListHandler
{
public:
ListHandler(const vector<int> &list)
: list_m(list)
{
}
private:
vector<int>& list_m;
};
初始化列表是冒号后的位,但在正文之前。
但是,这不等同于你的第二个例子,它在析构函数中使用指针和调用delete
。这是第三种方式,ListHandler承担列表的所有权。但代码存在危险,因为通过调用delete
,它假定列表已分配new
。澄清此策略的一种方法是使用标识所有权更改的命名约定(例如“采用”前缀):
ListHandler::ListHandler(vector<int> *adoptList)
: list_m(adoptList)
{
}
(除了名称更改和初始化列表的使用外,这与您的相同。)
所以现在我们已经看到了三个选择:
new
创建的列表的所有权。还有更多选择,例如引用计数的智能指针。
答案 4 :(得分:0)
没有一种“正确的方式”。然而,你的第二个例子是非常差的样式,因为ListHandler在构造时获取向量的所有权。如果可能的话,每个new
都应与其delete
密切配对 - 严肃地说,这是一个非常高的优先级。
如果vector
和ListHandler
一样长,那么它可能会在里面中运行ListHandler。如果将它放在堆上,它不会占用更少的空间。实际上,堆增加了一些开销。所以这根本不是new
的工作。
你也可以考虑
ListHandler::ListHandler(vector<int> &list) {
this->list.swap( list );
}
如果要清除初始化列表并避免复制向量内容的时间和内存开销。