我希望了解如何在C ++中实现vector
。有一个previous question问了这个,所以我看了一下,我有一个小问题。假设链接问题中的实现是正确的,让我们看一下这段代码:
int main(){
Vector<int> test2 = test_Vector();
cout << test2[0] << endl;
return 0;
}
// below is NOT the STL vector object, but the one in the linked question,
// in which the asker tries to implement STL vector himself/herself
Vector<int> test_Vector(){
Vector<int> test;
test.push_back(5);
return test;
}
据我了解,test
Vector
对象是在本地创建的,所以当test_Vector
方法返回时,本地对象超出范围,从而调用析构函数和{{ 1}} - 动态数组。由于代码实际工作并且打印了5,我想我错了。什么是正确的解释?
答案 0 :(得分:3)
你是对的,但你错过了一件重要的事情。
因为您要返回Vector<int>
,所以您应该将其视为已复制。这通常会调用复制构造函数,该构造函数将test
复制到Vector<int>
的新实例中。复制构造函数在链接问题中实现为:
template<class T>
Vector<T>::Vector(const Vector<T> & v)
{
my_size = v.my_size;
my_capacity = v.my_capacity;
buffer = new T[my_size];
for (int i = 0; i < my_size; i++)
buffer[i] = v.buffer[i];
}
请注意,由于返回值优化,可能无法调用复制构造函数(请参阅下面的注释中的头发拆分)。在许多情况下,允许编译器优化副本,而C ++标准允许此优化可能会改变程序行为。
无论是复制对象还是应用RVO,您都应该使用相同的东西。如果您遵循正常的面向对象实践,优化不应该破坏您的对象。
您应该始终考虑函数返回值按值传递(即复制)而不考虑类型,然后考虑您的编译器可能正在执行RVO。重要的是不要忘记Rule of Three(或四或五)。
答案 1 :(得分:1)
他提供了一个公共拷贝构造函数(从技术上讲,他没有使拷贝构造函数成为私有的),因此标准的C ++逻辑启动并生成要返回的对象的副本。新对象是main
的本地对象。在复制构造函数中,新内存为malloc
并且数据被复制。如果他没有提供复制构造函数,它将访问无效内存(尝试从已释放的指针访问内存)
答案 2 :(得分:1)
当返回test
时,将调用其复制构造函数(理论上),该构造函数分配新的内存块并复制test
的内容。 test
堆栈上的原始test_Vector
被破坏(理论上)并且test2
被分配了副本,这意味着将调用赋值运算符(理论上),它将再次分配内存和从返回时创建的临时对象复制数据。从test_Vector
返回的临时对象的析构函数被调用(理论上)。
正如你所看到的,如果没有编译器优化,这就是地狱:)如果你不做任何过于巴洛克式的事情并且编译器很聪明并且你的情况就这么简单,那么可以跳过“理论上的”。有关C ++ 11的故事更新,请参阅this。