【发布时间】:2012-05-21 15:09:33
【问题描述】:
情况:我正在实现一个类似列表的容器,该容器支持 Pop() 函数,该函数应该向用户返回存储在容器前面的 const char*。但是,作为实现者,我不确定是否应该返回原始的 const char*(从容器中删除节点指针,但不对 const char* 本身调用 delete),或者是否应该分配新的内存和返回元素的副本。
从课程和项目中,我遇到了那些总是支持复制的人,因此以前返回的引用(来自 getter 等)和指向 const char* 的指针不会改变弹出的版本,但由于这种方法需要额外的分配和strcpy,我想我会问是否只是简单地返回原始的、未删除的指向 const char 的指针而不删除它真的是一个问题。这是 WITH 分配和复制方法的代码 sn-p(然后删除原始引用):
const char* LinkedList::PopHeadString()
{
node* deletehead = head_;
char* output = NULL;
if (head_ != NULL && GetHeadType() == STRING) {
output = new char[strlen(head_->en.data.str) + 1];
strcpy(output, head_->en.data.str);
head_ = head_->next;
delete deletehead->en.data.str;
delete deletehead;
--nEntries_;
}
return output;
}
既然 Pop() 是一种常见的容器操作,我想我会问一般的方法是什么。
【问题讨论】:
-
STL 的解决方案是
pop()根本不返回任何东西。如果用户想要该对象,他们会使用back()获得对它的引用——当然,如果他们在调用pop()后需要使用该对象,则需要复制。此外,指针的 STL 容器仅假定指针的所有权,而不是指向的对象的所有权。 -
.. 因此,如果我遵循 STL 约定,假设存储(插入)指针的所有权但自己从未调用 new/delete,那么这是否也意味着容器的 STL 复制构造函数是浅拷贝?例如,如果我的一个成员函数应该返回一个新列表,其中包含第一个元素之后的所有元素(即 GetRemainder),那么我将创建一个副本列表,其中的指针指向与原始相同的动态内存地址?
-
是的。容器对值语义进行操作,因此如果您创建
std::list<int*>类型的对象,它会将指针视为值。因此,如果您复制列表,它会复制指针,并且不会尝试猜测您使用指针的目的。请注意,这通常是正确的。在我的观察中,C 风格的字符串确实是唯一常见的例外。当然,普遍的看法是你不应该在 C++ 中使用 C 风格的字符串:你应该使用std::string。 -
感谢您的建议。我很想使用字符串,但除了我被禁止使用 STL 之外,我还考虑让我的容器异构(每个元素可能是一个字符串、另一个分支列表或要执行的函数指针在后面的元素上),可能有一个联合,在这种情况下,包含指针可能比包含对象更有效。不过,浅拷贝仍然是最好的吗?
typedef union { const char* str; LinkedList* list; int (*proclist)(int, LinkedList); // func to execute on list } content;