std :: vector push_back和类构造函数没被调用?

时间:2012-05-26 09:05:10

标签: c++ vector

我有这样的课程

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));

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

调用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.

2 个答案:

答案 0 :(得分:4)

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

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

编辑:你为什么要编写自己的资源管理类?您只需将unique_ptr与自定义删除器一起使用即可。还有你自己的RTTI?

每个被破坏的对象必须已经构建完毕。标准中没有违反此规则的规则。 RVO和NRVO在您启动时才会出现问题,例如,在构造函数/析构函数中修改全局变量。否则,它们对程序的正确性没有影响。这就是他们成为标准的原因。你必须做错其他事。

最终,我还不确定WTF究竟发生在你身上,为什么它不起作用或者什么&#34;工作&#34;应该。发布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次。 一个构造函数被调用六次。不是你想要的那个。

答案 1 :(得分:0)

确定。我一直在阅读更多关于不同容器的内在函数的内容,显然,我正在努力完成的工作是 std :: deque