我知道在C++中为基类声明虚拟析构函数是一个好习惯,但是virtual即使对于作为接口的抽象类来说,声明析构函数总是很重要吗?请提供一些理由和示例原因.
考虑:
delete new std :: string [2];
delete [] new std :: string;
Run Code Online (Sandbox Code Playgroud)
每个人都知道第一个是错误.如果第二个不是错误,我们就不需要两个不同的运算符.
现在考虑:
std :: unique_ptr <int> x (new int [2]);
std :: unique_ptr <int> y (new int);
Run Code Online (Sandbox Code Playgroud)
是否x知道使用delete[]而不是 delete?
背景:当我认为指针的数组类型限定将是一个方便的语言功能时,这个问题浮现在我脑海中.
int *[] foo = new int [2]; // OK
int * bar = new int; // OK
delete [] foo; // OK
delete bar; // OK
foo = new int; // Compile error
bar = new int[2]; // Compile error
delete foo; …Run Code Online (Sandbox Code Playgroud) 由于boost::/std::shared_ptr具有类型擦除删除器的优点,你可以做很好的事情
#include <memory>
typedef std::shared_ptr<void> gc_ptr;
int main(){
gc_ptr p1 = new int(42);
gc_ptr p2 = new float(3.14159);
gc_ptr p3 = new char('o');
}
Run Code Online (Sandbox Code Playgroud)
由于保存了正确的删除器,这将正确删除所有指针.
如果您确保始终使用shared_ptr<Interface>(或make_shared<Interface>)创建接口的每个实现,您实际上是否需要virtual析构函数?virtual无论如何我会声明它,但我只是想知道,因为shared_ptr它将始终删除它初始化的类型(除非给出另一个自定义删除器).
当第二个示例只调用基类中的析构函数时,为什么在使用std :: shared_ptr deallocation从基类和派生类调用析构函数?
class Base
{
public:
~Base()
{
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base
{
public:
~Derived()
{
std::cout << "Derived destructor" << std::endl;
}
};
void virtual_destructor()
{
{
std::cout << "--------------------" << std::endl;
std::shared_ptr<Base> sharedA(new Derived);
}
std::cout << "--------------------" << std::endl;
Base * a = new Derived;
delete a;
}
Run Code Online (Sandbox Code Playgroud)
输出:
--------------------
Derived destructor
Base destructor
--------------------
Base destructor
Run Code Online (Sandbox Code Playgroud)
在这两种情况下我都期待相同的行为.
注意:我发现错误的来源实际上与shared_ptr无关,只是在错误消息中巧妙地伪装.因此,下面基本上是无稽之谈(不是答案,他们很好)
-
我在使用shared_ptr(目前的提升)时遇到了一些麻烦,我需要简单地将指针转发给另一个函数.使用本机指针,介入函数不需要访问类的定义,但是使用smart_ptr它就可以了.有什么方法可以避免这种情况吗?
例如,给定目标函数:
void func( shared_ptr<SomeClass> const & obj )
Run Code Online (Sandbox Code Playgroud)
该const &负责的问题的一部分,而是说我们有一个getter类获得对象为其他类,如:
shared_ptr<SomeClass> someClassInstance();
Run Code Online (Sandbox Code Playgroud)
这里是我想简单地组装参数并转发到目标函数的地方:
func( someClassInstance() );
Run Code Online (Sandbox Code Playgroud)
使用普通指针,代码中的这一点可以简单地使用前向声明SomeClass,但是smart_ptr需要具有完整定义(可能是因为smart_ptr可能需要删除该类).
现在,如果someClassInstance要返回const &这个问题实际上会消失,因为介入的代码不会复制任何对象.但是,出于线程安全原因,getter函数必须返回副本.
无论如何我可以实现这种类型的智能指针参数转发而不需要类定义吗?也就是说,我可以像在这种情况下使用传统指针一样使用智能指针.
-
更新:写一个小测试答案是正确的,前向声明就足够了.然而海湾合作委员会仍然在一种情况下抱怨.我将不得不弄清楚导致它失败的原因(在这种特殊情况下).
我现在暂时关闭这个问题,或者什么?
我们知道如果有虚函数那么基类析构函数也应该被标记为虚拟,否则当显式地如果我们希望删除带有基类指针的派生对象,则基础析构函数应该被标记为虚拟,否则是未定义的行为.deleted使用基类指针时它是未定义的行为
例如,
struct Base {
virtual void greet() { std::cout << "base\n"; }
};
struct Derived : public Base {
virtual void greet() override { std::cout << "derived\n"; }
};
Run Code Online (Sandbox Code Playgroud)
呼叫
Base *b = new Derived;
b->greet();
delete (b);
Run Code Online (Sandbox Code Playgroud)
-wdelete-non-virtual-dtor时,clang(类似gcc)会发出这样的警告:
delete called on 'Base' that has virtual functions but non-virtual destructor
Run Code Online (Sandbox Code Playgroud)
但他们都没有报告智能指针的警告:
std::unique_ptr<Base> sb = std::make_unique<Derived>();
// std::unique_ptr<Base> sb = std::unique_ptr<Derived>(new Derived);
sb->greet();
Run Code Online (Sandbox Code Playgroud)
我想这仍然导致未定义的行为,对吧?
我们假设我有两个类:
class Base{};
class Derived: public Base{};
Run Code Online (Sandbox Code Playgroud)
没有d tor,在这种情况下如果我声明变量:
Base b;
Derived d;
Run Code Online (Sandbox Code Playgroud)
我的编译器会为我生成,我的问题是,默认的b and d是否是虚拟的?
在以下示例中:
class Base {
protected:
~Base() {
cout << "B\n";
}
};
class Derived : public Base {
public:
virtual ~Derived(){
cout << "D\n";
}
};
int main() {
Base *myBase_raw = new Derived();
delete myBase_raw;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
你期望得到:
错误:'virtual Base :: ~Base()'在此上下文中受到保护delete myBase_raw;
这很好,是阻止人们删除对象的有用工具.这也是如此std::unique_ptr.但是当你将原始指针交换为a时std::shared_ptr,它会正确编译:
int main() {
std::shared_ptr<Base> myBaseS(new Derived());
}
Run Code Online (Sandbox Code Playgroud)
似乎运行删除对象并调用Base和Derived析构函数(实例).根据cppreference:
使用delete-expression或在构造期间提供给shared_ptr的自定义删除器来销毁对象.
由于我没有提供自定义删除器,因此应该调用delete.以上怎么可能?
它 广泛 知道,你可以使用shared_ptr一个存储指向不完全类型,只要指针可以(有良好定义的行为)的施工过程中被删除shared_ptr.例如,PIMPL技术:
struct interface
{
interface(); // out-of-line definition required
~interface() = default; // public inline member, even if implicitly defined
void foo();
private:
struct impl; // incomplete type
std::shared_ptr<impl> pimpl; // pointer to incomplete type
};
Run Code Online (Sandbox Code Playgroud)
[main.cpp中]
int main()
{
interface i;
i.foo();
}
Run Code Online (Sandbox Code Playgroud)
[interface.cpp]
struct interface::impl
{
void foo()
{
std::cout << "woof!\n";
}
};
interface::interface()
: pimpl( new impl ) // `delete impl` is well-formed at this point
{}
void interface::foo() …Run Code Online (Sandbox Code Playgroud) 我一直在考虑从C++ 11中继承STL容器.我知道如果没有一些考虑因素就不应该这样做,因为没有虚拟析构函数.
根据我的理解,使用typedef是为STL容器命名的首选方法.
但是,typedef本身并非没有问题.首先,它们不能轻易地向前声明,并且两个typedef可能意外地是相同的类型.
请考虑以下事项:
typedef std::vector<int> vec_a_t;
typedef std::vector<float> vec_b_t;
void func(const vec_a_t& v);
void func(const vec_b_t& v);
Run Code Online (Sandbox Code Playgroud)
这两个函数的行为应根据逻辑类型vec_a_t或不同而有所不同vec_b_t
这种情况将正常工作,直到有人改变vec_a_t到
typedef std::vector<float> vec_a_t;
Run Code Online (Sandbox Code Playgroud)
现在打电话func()突然变得含糊不清.一个现实的例子func()是
std::ostream& operator<<(std::ostream& ost, const vec_a_t& v);
Run Code Online (Sandbox Code Playgroud)
现在,如果我们改为继承
class Vector : public std::vector<int>
{};
std::ostream& operator<<(std::ostream& ost, const Vector& v);
Run Code Online (Sandbox Code Playgroud)
也可以宣布
class Vector2 : public std::vector<int> {};
std::ostream& operator<<(std::ostream& ost, const Vector2& v);
Run Code Online (Sandbox Code Playgroud)
这显然是消除歧视.
但是,因为std::vector没有从它们派生的虚拟析构函数,所以这是错误的并且可能导致问题.
相反,我们尝试
class Vector : private std::vector<int>
{
public:
using::size;
//Add …Run Code Online (Sandbox Code Playgroud) 很抱歉这个漫长而令人困惑的标题.
我有这样的类头文件
#pragma once
#include <thread>
#include <boost/asio.hpp>
#include <another3rdpartylib/doodads.h>
class A {
public:
A();
Method1();
Method2();
private:
std::thread thread;
boost::asio::socket socket;
another3dpartylib::doodad gizmo;
}
Run Code Online (Sandbox Code Playgroud)
现在,班级的用户不会也不应该关心私人部分.如何在不拖动的情况下允许用户包含该类<thread>,<boost/asio.hpp>并且<another3rdpartylib/doodads.h>?
从技术上讲,用户唯一应该关心的是sizeof(A).我错了吗?
有一个虚拟类作为回调接口,我既不能修改,也不能要求作者修复。类的唯一成员是很多可以覆盖的虚方法,以便让库回调到我的代码中。为了获得一些回调机会,我应该为那个虚拟类创建一个派生类,并覆盖相应的虚拟方法。如果我对某些回调机会不感兴趣,我只需要避免覆盖它们。
但是,该接口类的声明有一个缺陷——它的析构函数没有声明为 virtual。
例如:
class callback_t {
public:
virtual void onData( int ) {};
};
Run Code Online (Sandbox Code Playgroud)
我创建了一个子类并且不覆盖析构函数,但是当我删除类的动态对象时child_t,我遇到来自编译器的警告(gcc9 with C++17):
删除具有非虚拟析构函数的多态类类型“child_t”的对象可能会导致未定义的行为。
class child_t : public callback_t {
public:
~child_t() {
// release things specific to the child...
};
void onData( int ) override {
// do things I want when onData
};
private:
int m_data = 0;
};
int main() {
child_t* pc = new child_t;
// pass pc into the routines of the library
// …Run Code Online (Sandbox Code Playgroud) c++ polymorphism overriding derived-class virtual-destructor
我的代码有什么问题:
class Game{
private:
mtm::Dimensions dimensions;
std::vector<std::shared_ptr<Character>> board;
};
std::shared_ptr<Character> Game::makeCharacter(CharacterType type, Team team, units_t health,
units_t ammo, units_t range, units_t power) {
std::shared_ptr<Character> out = nullptr;
if (type ==SNIPER)
out=mtm::Sniper(team,health,power,ammo,range);
return out;
}
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
没有可行的重载 '='
out=mtm::狙击手(团队,健康,力量,弹药,射程);
注意:Sniper继承自抽象类Character。
我该如何解决这个问题?
c++ ×13
c++11 ×8
shared-ptr ×5
inheritance ×3
boost ×2
class ×1
destructor ×1
methods ×1
overriding ×1
pointers ×1
polymorphism ×1
stl ×1
unique-ptr ×1
vector ×1