当我执行std::vector = std::vector时,旧的std::vector值会发生什么变化?

5
我有以下代码片段:

std::vector<std::string> v1;
v1.push_back("Hello");
v1.push_back("World");

std::vector<std::string> v2;
v2.push_back("Good");
v2.push_back("Bye");

v1 = v2;

向量 v1 的旧值会发生什么?

  • 旧值将立即被销毁吗?

还是

  • 它们将在向量 v1 销毁时被销毁。那么我如何立即释放它们?
2个回答

7
根据参考文献123,在调用之前容器中保存的任何元素都会被赋值或销毁。因此,在您的示例中,原始的底层std::string值将调用std::string::operator=,它们(底层的std::string本身)不会被销毁。如果被赋值的向量大于被赋值的向量,则会对向量中的元素调用析构函数,例如:
std::vector<std::string> v1;
v1.push_back("Hello");
v1.push_back("There");
v1.push_back("World");

std::vector<std::string> v2;
v2.push_back("Good");
v2.push_back("Bye");

v1 = v2;

在这个例子中,"Hello""There"std::string 值将分别被赋值为 "Good""Bye",而 "World" 的第三个字符串将被销毁。
需要记住的是,这仅适用于向量中包含的元素,例如以下代码:
std::vector<int*> v1;
v1.push_back(new int(42));
v1.push_back(new int(24));
v1.push_back(new int(38));

std::vector<int*> v2;
v2.push_back(new int(32));
v2.push_back(new int(23));

v1 = v2;

在这段代码中,发生了内存泄漏,因为 v1 是一个包含指针的向量,这些指针本身被分配/销毁,而不是它所指向的值。这个例子等同于以下内容:
int* x = new int(42);
int* y = new int(24);
x = y; // memory leak here

如果您想从向量中删除元素(这样会调用容器中每个元素的析构函数),可以使用clear方法,它会清除向量中的所有元素;或者您也可以使用erase方法,该方法可以删除单个或多个元素。
对于clearerase,适用相同的规则;如果底层类型是声称了内存的指针类型,那么您需要确保在向量中删除元素之前将其delete,例如:
template < typename IteratorType >
void delete_elements(IteratorType start, IteratorType end)
{
    while (start != end) {
        delete (*start); // or delete[]
        ++start;
    }
}

std::vector<int*> v1;
v1.push_back(new int(42));
v1.push_back(new int(24));
v1.push_back(new int(38));

delete_elements(v1.begin(), v1.end());

如果你想看到这个任务的实际应用,可以使用以下代码所示的小型测试类:

#include <iostream>
#include <string>
#include <vector>

#define outi(v) std::cout << v << ", i = " << i << std::endl

class tester {
    public:
        tester() : i(42) { outi("default ctor"); }
        tester(int x) : i(x) { outi("implicit ctor"); }
        ~tester() { outi("dtor"); }
        tester(const tester& cp) : i(cp.i) { outi("copy ctor"); }
        tester& operator=(const tester& cp) {
            this->i = cp.i;
            outi("operator=");
            return *this;
        }
        // for std::cout << tester;
        friend std::ostream& operator<<(std::ostream& o, const tester& t) {
            o << t.i; return o;
        }
    private:
        int i;
};

template < typename itr >
static void printall(itr start, itr end)
{
    while (start != end) {
        std::cout << (*start) << std::endl;
        ++start;
    }
}

int main(int argc, char* argv[])
{
    std::vector<tester> v1;
    std::cout << "create v1 elements" << std::endl;
    v1.push_back(10); // implicit ctor calls
    v1.push_back(24);
    v1.push_back(33);
    printall(v1.begin(), v1.end());
    std::vector<tester> v2;
    std::cout << "create v2 elements" << std::endl;
    v2.push_back(tester(100));
    v2.push_back(tester(99));
    printall(v2.begin(), v2.end());
    std::cout << "v1 = v2" << std::endl;
    //v1.clear(); // uncomment to call dtor's
    v1 = v2;
    printall(v1.begin(), v1.end());
    return 0;
}

这个程序的输出可能如下所示:
create v1 elements
implicit ctor, i = 10
copy ctor, i = 10
dtor, i = 10
implicit ctor, i = 24
copy ctor, i = 10
dtor, i = 10
copy ctor, i = 24
dtor, i = 24
implicit ctor, i = 33
copy ctor, i = 10
copy ctor, i = 24
dtor, i = 10
dtor, i = 24
copy ctor, i = 33
dtor, i = 33
10
24
33
create v2 elements
implicit ctor, i = 100
copy ctor, i = 100
dtor, i = 100
implicit ctor, i = 99
copy ctor, i = 100
dtor, i = 100
copy ctor, i = 99
dtor, i = 99
100
99
v1 = v2
operator=, i = 100
operator=, i = 99
dtor, i = 33
100
99
dtor, i = 100
dtor, i = 99
dtor, i = 100
dtor, i = 99

我说“可能”是因为你的编译器可以选择略微不同的构造函数/赋值顺序,但结果将是相同的。

希望这能有所帮助。


2
< p > 当 < code > v1 被赋值时,旧的 < code > v1 值被销毁,因为赋值会删除先前的内容。 < /p > < p > 如果要立即清除向量而不分配新值,则可以使用 < code > clear 方法或 < code > resize 方法。 < /p >

1
请注意:旧的向量条目可能没有被“销毁”(而是使用赋值运算符来更改值)。不确定您是否有意区分“销毁”和“摧毁”(如果是这样,不确定原帖作者是否理解)。 - M.M
@M.M. 这不是最好的答案。在编辑窗口消失之前,我意识到自己回答了一些完全无意义的东西,完全误读了问题的代码。然后当我添加第二段时,我发现我把它添加到了Joachin Pileborg(现已删除)的答案中,而不是我的答案中。这是在喝咖啡之前发生的。 - Cheers and hth. - Alf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接