Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
句柄类中的删除对象可能会导致未定义的行为 < >我有如下代码:KoeNo.MoO加速C++页面255,定义了一个通用句柄类句柄。句柄用于管理对象的内存: #include <iostream> #include <stdexcept> ///Handle template <class T> class Handle { public: Handle() : p(0) {} Handle &operator=(const Handle &); T *operator->() const; ~Handle() { delete p; } Handle(T *t) : p(t) {} private: T *p; }; template <class T> Handle<T> &Handle<T>::operator=(const Handle &rhs) { if (&rhs != this) { delete p; p = rhs.p ? rhs.p->clone() : 0; } return *this; }; template <class T> T *Handle<T>::operator->() const { if (p) return p; throw std::runtime_error("error"); }; class test_classA { friend class Handle<test_classA>; private: virtual test_classA *clone() const { return new test_classA; } public: virtual void run() { std::cout << "HiA"; } }; class test_classB : public test_classA { private: virtual test_classB *clone() const { return new test_classB; } public: virtual void run() { std::cout << "HiB"; } }; int main() { Handle<test_classA> h; h = new test_classA; h->run(); return 0; }_C++_Pointers_Virtual Destructor - Fatal编程技术网

句柄类中的删除对象可能会导致未定义的行为 < >我有如下代码:KoeNo.MoO加速C++页面255,定义了一个通用句柄类句柄。句柄用于管理对象的内存: #include <iostream> #include <stdexcept> ///Handle template <class T> class Handle { public: Handle() : p(0) {} Handle &operator=(const Handle &); T *operator->() const; ~Handle() { delete p; } Handle(T *t) : p(t) {} private: T *p; }; template <class T> Handle<T> &Handle<T>::operator=(const Handle &rhs) { if (&rhs != this) { delete p; p = rhs.p ? rhs.p->clone() : 0; } return *this; }; template <class T> T *Handle<T>::operator->() const { if (p) return p; throw std::runtime_error("error"); }; class test_classA { friend class Handle<test_classA>; private: virtual test_classA *clone() const { return new test_classA; } public: virtual void run() { std::cout << "HiA"; } }; class test_classB : public test_classA { private: virtual test_classB *clone() const { return new test_classB; } public: virtual void run() { std::cout << "HiB"; } }; int main() { Handle<test_classA> h; h = new test_classA; h->run(); return 0; }

句柄类中的删除对象可能会导致未定义的行为 < >我有如下代码:KoeNo.MoO加速C++页面255,定义了一个通用句柄类句柄。句柄用于管理对象的内存: #include <iostream> #include <stdexcept> ///Handle template <class T> class Handle { public: Handle() : p(0) {} Handle &operator=(const Handle &); T *operator->() const; ~Handle() { delete p; } Handle(T *t) : p(t) {} private: T *p; }; template <class T> Handle<T> &Handle<T>::operator=(const Handle &rhs) { if (&rhs != this) { delete p; p = rhs.p ? rhs.p->clone() : 0; } return *this; }; template <class T> T *Handle<T>::operator->() const { if (p) return p; throw std::runtime_error("error"); }; class test_classA { friend class Handle<test_classA>; private: virtual test_classA *clone() const { return new test_classA; } public: virtual void run() { std::cout << "HiA"; } }; class test_classB : public test_classA { private: virtual test_classB *clone() const { return new test_classB; } public: virtual void run() { std::cout << "HiB"; } }; int main() { Handle<test_classA> h; h = new test_classA; h->run(); return 0; },c++,pointers,virtual-destructor,C++,Pointers,Virtual Destructor,我不太明白这个警告。handle类会自动删除析构函数中的指针*p,而不管其类型如何,因此潜在的陷阱在哪里?您的警告说明了一切。类A是多态的,但析构函数是非虚拟的。当基类没有虚拟析构函数时,通过指向基类的指针删除派生类的对象是未定义的行为 在您的特定示例中,没有未定义的行为,因为您没有派生类的对象,但编译器可能无法确定它,因此不管怎样它都会警告您。问题是,如果处理的对象属于模板实例类型的子类,则会发生错误的删除 在您的情况下,如果您的手柄h;将处理类型为test\u classB的对象…句柄h具有

我不太明白这个警告。handle类会自动删除析构函数中的指针*p,而不管其类型如何,因此潜在的陷阱在哪里?

您的警告说明了一切。类A是多态的,但析构函数是非虚拟的。当基类没有虚拟析构函数时,通过指向基类的指针删除派生类的对象是未定义的行为


在您的特定示例中,没有未定义的行为,因为您没有派生类的对象,但编译器可能无法确定它,因此不管怎样它都会警告您。

问题是,如果处理的对象属于模板实例类型的子类,则会发生错误的删除

在您的情况下,如果您的手柄h;将处理类型为test\u classB的对象…

句柄h具有类型句柄,因此它将存储指向test\u classA的指针并调用test\u classA的析构函数。但是,您可以在句柄中存储指向test_classB的指针,在这种情况下,不会调用test_classB析构函数,因为test_classA析构函数不是虚拟的:

h = static_cast< test_classA * >(new test_classB);

还注意到,这个句柄类名称不太好,它本质上是一个智能指针类。C++中的

,如果你有一个基类,这里有其他类的TestJulax,这里是TestJavaCB,如果类型test\u classA的指针实际上可能指向类型test\u classB的对象,那么在删除这些指针时必须小心。请注意,您在这里编写的代码中正是这样做的

如果执行类似操作,则需要为基类test_classA提供一个虚拟析构函数,如下所示:

class test_classA {
public:
    virtual ~test_classA() = default;
    // ...
};

这样,当C++试图删除TestObjyLa类型的指针时,它知道所讨论的指针可能实际上没有指向TestJuleA级对象,并且将正确调用右析构函数。

顺便说一下,这个问题完全独立于包装器类型。你可以通过写作得到同样的问题

test_classA* ptr = new test_classB;
delete ptr; // <--- Warning! Not good unless you have a virtual dtor.

该警告是由于基类的析构函数不是虚拟的。如果你想使用你的类,比如创建一个带有基类指针的向量,其中指向的对象是一个派生类,那么你将有未定义的行为

另一件需要提及的事情是,为了获得对克隆函数的访问权,您将Handle类声明为类test_classA的朋友。请注意,friend关键字不是可传递的,因此在派生类中,Handle类无法访问clone函数

最后,我不太清楚你的克隆功能。让我们看看主要功能:

Handle<test_classA> h;
h = new test_classA
您可以使用默认构造函数实例化一个类句柄,该构造函数将p初始化为NULL指针,顺便说一下,如果使用C++11,则最好使用NULL ptr初始化它,而不是使用0或NULL 在下一行中,您调用实例h的运算符=。这里,运算符=等待句柄类。因此表达式newtest_classA将隐式调用句柄类构造函数HandleT*t:pt{}。然后,这将在operator=函数中使用,在该函数中检查rhs.p是否为NULL。由于它不为null,您将调用clone函数。您编写的函数相当于rhs.p->clone,因此它不是被调用的句柄类“operator->”,而是将在堆中再次创建内存的指针p。
我想这不是你想要的。

离题:注意你的问题。Handle缺少复制构造函数。@user4581301不是HandleT*t:pt{}复制构造函数吗?HandleT*t:pt{}是将p初始化为给定值的构造函数。复制构造函数基于现有实例创建一个新实例,看起来像:Handleconst Handle&source。在这种情况下,您可能不希望进行任何复制,并且应该删除复制构造函数Handleconst Handle&source=delete;另一种方法是为p创建一个新的T,指向:Handleconst Handle&source:pnew Tsource.p{}但是,您不希望两个句柄具有相同的p。注意,这不是OP所做的。在提供的代码中,实际上没有未定义的行为。
Handle<test_classA> h;
h = new test_classA