通过引用传递给STL容器的对象的生命周期

时间:2010-08-23 19:28:00

标签: c++ stl reference

我是一名经验丰富的编码员,但我仍然是STL的新手,并且刚遇到这个问题:

据我所知,STL容器并不意味着复制它们包含的对象,或者影响它们的生命周期,但实验上我看到了不同的结果。

特别是,如果字符串类在超出范围之前存储在容器中,则它们可以在销毁时将其底层存储的第一个字符清零。例如,请考虑以下示例:

使用namespace std;

queue<string> strQueue;

const char *genStr(int i)
{
    ostringstream os;
    os << "The number i is " << i;
    strQueue.push(os.str());
    return strQueue.back().data();
}

void useStr()
{
    while(!strQueue.empty())
    {
        cout << strQueue.front() << endl;
        strQueue.pop();
    }
}

int main(int argc, char **argv)
{
    for(int i = 0; i < 40; i++)
    {
        printf("Retval is: %s\n", genStr(i));
    }
    useStr();

    return 0;
}

当genStr()退出时,字符串超出范围,我希望printf只输出“Retval is:”,或者至少调用useStr()来提供未定义的结果,作为内存被额外调用的重复分配踩了一脚,但两者都返回了相应的存储字符串,并且没有失败。

我想知道为什么会发生这种情况,但取而代之的是,我很高兴知道我是否可以依赖任何旧物体发生的这种影响。

由于

4 个答案:

答案 0 :(得分:8)

  

据我所知,STL容器   并不意味着复制那些对象   它们包含

好的,我们就在那里停下来。 STL容器 经常复制其内容。它们在插入时复制它们,它们在容器自动或显式调整大小时复制它们,并在复制容器本身时复制它们。很多很多的复制。

我不确定您认为STL容器不会复制其内容的位置。我能想到的唯一一点是,如果你将一个指针插入一个STL容器中,它将复制指针本身而不是指向数据。

此外,您的代码中没有任何引用,所以我对这个问题的标题所引用的内容感到困惑。

答案 1 :(得分:5)

  

STL容器并不意味着复制它们包含的对象

STL 所有关于制作副本。它会在您插入对象时生成它们,并且有时在底层存储调整大小时生成它们。如果要复制的对象在函数超出范围时失效(例如,如果添加指向局部变量的指针,而不是复制局部变量),则可能会损坏代码。

在您的情况下,您没有复制对字符串的引用,而是复制字符串。这个复制的字符串然后存在于strQueue的范围内,因此您看到的行为是完全有效和可靠的。

这是另一个误解清除:

  

特别是字符串类,它意味着在销毁时将其底层存储的第一个字符清零

C ++并不倾向于做那种事情。这将是一个隐藏的成本,C ++讨厌隐藏的成本:)字符串析构函数不会触及内存,因为一旦析构函数退出,该对象就不再存在。访问它是未定义的行为,因此C ++实现将在定义良好的代码中执行最快且最少浪费的任何操作。

答案 2 :(得分:0)

容器的内容是对象的副本,而不是实际的对象。同样,你得到的也是一个副本。只要容器在范围内,就可以访问这些对象。

答案 3 :(得分:0)

所有“STL”(我讨厌那个术语)集合存储传递给它们的对象的副本,因此集合中对象的生命周期完全独立于原始对象。在正常情况下,集合的对象副本将保持有效,直到您从集合中删除它或销毁集合。