我有两行代码,我想解释一下。你可以告诉我多少。主要是每个人的好处以及幕后发生的事情等等。
这里有两个结构作为例子:
struct Employee
{
std::string firstname, lastname;
char middleInitial;
Date hiringDate; // another struct, not important for example
short department;
};
struct Manager
{
Employee emp; // manager employee record
list<Employee*>group; // people managed
};
在上述结构中使用哪两种更好?为什么?
list<Employee*>group;
list<Employee>group;
答案 0 :(得分:6)
首先,std::list
是一个双向链表。因此,这两个声明都创建了一个员工链表。
list<Employee*> group;
这会创建一个指向Employee
个对象的指针列表。在这种情况下,需要有一些其他代码来分配每个员工,然后才能将其添加到列表中。同样,每个员工必须单独删除,std :: list不会为您执行此操作。如果要与其他实体共享员工列表,这将是有意义的。将员工放在智能指针类中以防止内存泄漏可能会更好。像
typedef std::list<std::shared_ptr<Employee>> EmployeeList;
EmployeeList group;
这一行
list<Employee>group;
按值创建 Employee
个对象的列表。在这里,您可以在堆栈上构建Employee对象,将它们添加到列表中,而不必担心内存分配。如果员工列表未与其他任何内容共享,这是有意义的。
答案 1 :(得分:1)
一个是指针列表,另一个是对象列表。如果你已经分配了对象,那么第一个是有道理的。
答案 2 :(得分:1)
如果您将“人员管理”存储在另一个位置,您可能想要使用第二个。详细说明:如果您还有一个公司员工的全局列表,您可能希望有指针,因为您希望在位置之间共享代表员工的对象(例如,如果您更新名称,则更改为“已查看”从两个地方)。
如果您只想知道“为什么结构列表而不是指针列表”,答案是:更好的内存局部性,不需要取消分配单个Employee对象,但要小心每个分配到/来自列表节点(例如,通过迭代器及其*运算符)复制整个结构而不仅仅是指针。
答案 3 :(得分:1)
这两个列表很好,但它们需要完全不同的处理。
list<Employee*>group;
是指向Employee类型对象的指针列表,您将存储指向动态分配的对象的指针,并且您需要特别清楚谁将删除这些对象。
list<Employee>group;
是Employee类型的对象列表;您可以获得处理不需要内存管理的具体实例的好处(以及相关的性能成本)。
具体而言,与普通数组相比,使用std::list
的一个优点是,您可以拥有对象的列表,并避免处理动态内存分配的成本和风险和指针。
使用对象列表,您可以这样做,例如。克。
Employee a; // object allocated in the stack
list.push_back(a); // the list does a copy for you
Employee* b = new Employee....
list.push_back(*b); // the object pointed is copied
delete b;
使用指针列表,您必须始终使用动态分配,或者引用其生命周期长于列表的对象(如果可以保证的话)。
通过使用std ::指针列表,就内存管理而言,你或多或少与使用普通指针数组时的情况相同。您获得的唯一优势是列表可以动态增长而无需您的努力。
我个人认为使用指针列表没有多大意义;基本上,因为我认为应该通过智能指针使用指针(总是在可能的情况下)。所以,如果你真的需要指针,你会更好,IMO,使用boost提供的智能指针列表。
答案 4 :(得分:1)
第一个按指针存储对象。在这种情况下,您需要仔细记录谁拥有已分配的内存以及谁负责在完成后进行清理。第二个按值存储对象,并完全控制它们的生命周期。
使用哪一个取决于你在问题中没有给出的背景,虽然我赞成将第二个稍微作为默认值,因为它不会留下错误管理记忆的可能性。
但毕竟,小心考虑list
是否真的是适合您的容器选择。通常,它是一个满足特定需求的低优先级容器。对于随机访问容器,我几乎总是首先支持vector
和deque
,对于已订购的容器,我几乎总是支持set
和map
。
如果你确实需要在容器中存储指针,boost会提供为你管理内存的ptr-container类,或我建议存储某种智能指针,以便清理内存当不再需要对象时自动。
答案 5 :(得分:1)
很大程度上取决于你在做什么。对于初学者,你真的想要吗?
Manager
包含Employee
,而不是一个:经典
经理(一个经典的OO示例)的例子是:
struct Manager : public Employee
{
list<Employee*> group;
};
否则,您遇到的问题是您无法将经理纳入其中 另一位经理的小组;你只限于管理层的一个级别 层次结构。
第二点是,为了做出明智的决定,你
必须了解Employee
在该计划中的作用。如果Employee
只是一个值:一些硬数据,通常是不可变的(除了
分配完整的Employee
),然后是list<Employee> group
绝对是首选:除非必须,否则不要使用指针。如果
Employee
是一个“实体”,它模拟一些外部实体(比如说
公司的员工),你通常会把它变成不可复制的
不可分配,并使用list<Employee*>
(具有某种机制)
在员工被解雇时通知Manager
,并指出
对象被删除)。如果经理是员工,而你又不想
当它们被添加到一个组中时,这个事实就松了,那么你必须使用它
指针版本:多态性需要指针或引用才能工作
(你不能有一个参考容器)。
答案 6 :(得分:0)
如果您分别分配或访问结构,请使用第一个。
如果您仅通过列表分配/访问它们,请使用第二个。
答案 7 :(得分:0)
第一个定义了一个指向对象的指针列表,第二个定义了一个对象列表 第一个版本(带指针)是大多数程序员的首选。 主要原因是STL通过值复制元素使排序和内部重新分配更有效。
答案 8 :(得分:0)
您可能想要使用unique_ptr&lt;&gt;或auto_ptr&lt;&gt;或shared_ptr&lt;&gt;而不是普通的老*指针。如果没有使用非堆对象的预期使用而没有太多内存问题的整个方式,这会有一些...