1

我有这样的课

class variable
{
    public:
        variable(int _type=0) : type(_type), value(NULL), on_pop(NULL)
        {
        }

        virtual ~variable()
        {
            if (type)
            {
                std::cout << "Variable Deleted" <<std::endl;
                on_pop(*this);
                value=NULL;
            }
        }

        int     type;
        void*   value;
        typedef void(*func1)(variable&);
        func1 on_pop;
}

然后我将实例推送到 std::vector 中,如下所示:

stack.push_back(variable(0));

我希望变量的析构函数将被调用,但 if 直到将值分配给 type 才会进入,因为我希望在将实例复制到向量中时调用我提供的构造函数。但由于某种原因,它不是。

在调用 stack.push_back 后,析构函数(副本的?)运行并且类型具有一些随机值,就像从未调用构造函数一样。

我似乎无法弄清楚我做错了什么。请帮忙!^_^

编辑:

好的,这是一个自包含的示例来说明我的意思:

#include <iostream>
#include <vector>

class variable
{
    public:
        variable(int _type=0) : type(_type), value(NULL), on_pop(NULL)
        {
        }

        ~variable()
        {
            if (type)
            {
                std::cout << "Variable Deleted" <<std::endl;
                on_pop(*this);
                value=NULL;
            }
        }

        int     type;
        void*   value;

        typedef void(*func1)(variable&);
        func1 on_pop;
};

static void pop_int(variable& var)
{
    delete (int*)var.value;
}

static void push_int(variable& var)
{
    var.type = 1;
    var.value = new int;
    var.on_pop = &pop_int;
}

typedef void(*func1)(variable&);
func1 push = &push_int;

int main()
{
    std::vector<variable>   stack;

    stack.push_back(variable(0));
    push(stack[stack.size()-1]);

    stack.push_back(variable(0));
    push(stack[stack.size()-1]);

    stack.push_back(variable(0));
    push(stack[stack.size()-1]);

    return 0;
}

上面的程序输出以下内容:

Variable Deleted
Variable Deleted
Variable Deleted
Variable Deleted
Variable Deleted
Variable Deleted

Process returned 0 (0x0)   execution time : 0.602 s
Press any key to continue.
4

2 回答 2

4

欢迎来到 RVO 和 NRVO。这基本上意味着编译器可以跳过创建一个多余的对象——即使它的构造函数和析构函数有副作用。您不能依赖立即复制或移动到实际存在的对象。

编辑:vector根本无法省略中的实际值。只能省略中间变量variable(0)vector必须仍然像往常一样构造和销毁中的对象。这些规则仅适用于临时工。

编辑:您为什么要编写自己的资源管理课程?您可以简单地使用unique_ptr自定义删除器。还有你自己的 RTTI?

每个被破坏的对象都必须被构造。标准中没有违反这一点的规则。RVO 和 NRVO 仅在您开始时才会出现问题,例如,修改构造函数/析构函数中的全局变量。否则,它们对程序的正确性没有影响。这就是为什么他们是标准的。你一定做错了什么。

最终,我只是不确定 WTF 到底发生在你身上,以及为什么它不工作或“工作”应该是什么。发布 SSCCE。

编辑:根据您的 SSCCE,绝对没有任何问题。这完全是预期的行为。您没有遵守三原则——也就是说,您在析构函数中破坏了资源,但没有努力确保您确实拥有相关资源。您的编译器生成的复制构造函数正在破坏您的逻辑。您必须阅读关于 C++ 中资源处理的三法则、复制和交换以及类似的习惯用法,并且最好使用已经作为标准提供的智能指针,unique_ptr它没有这些问题。

毕竟,您创建了六个实例variable- 堆栈上的三个临时对象,向量内部的三个。所有这些都调用了它们的析构函数。问题是您从未考虑过复制操作或复制会做什么或这些临时对象会发生什么(提示:它们会被破坏)。

考虑同样的例子

int main()
{
    variable v(0);
    push_int(v);
    variable v2 = v;
    return 0;
}

变量v被构造并分配一个新的int,一切都是花花公子。但是等等,然后我们将它复制到v2. 编译器生成的构造函数复制所有位。然后两者v2v被销毁-但它们都指向相同的资源,因为它们都持有相同的指针。双重删除比比皆是。

您必须定义复制(共享所有权 - std::shared_ptr)或移动(唯一所有权 - std::unique_ptr)语义。

编辑:只是一个简短的说明。我观察到您实际上push直到它们已经在向量中之后才进入项目。但是,当您添加其他元素时必须调整向量的大小并且基本原因相同时,会观察到相同的效果。

析构函数被调用了 6 次。构造函数被调用六次只是不是你想要的那个。

于 2012-05-26T09:07:25.950 回答
0

行。我一直在阅读有关不同容器内在特性的更多信息,显然,我在这里尝试完成的工作是std::deque

于 2012-05-26T13:00:39.633 回答