Aku*_*ete 12 c++ polymorphism memory-management
在以下代码中:
class A {
};
class B : public A {
};
class C : public A {
int x;
};
int main (int argc, char** argv) {
A* b = new B();
A* c = new C();
//in both cases, only ~A() is called, not ~B() or ~C()
delete b; //is this ok?
delete c; //does this line leak memory?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当使用具有成员函数的非虚析构函数(如C类)调用类上的delete时,内存分配器可以告诉对象的正确大小是什么吗?如果没有,记忆是否泄露?
其次,如果类没有成员函数,并且没有明确的析构函数行为(比如B类),那么一切都好吗?
我问这个是因为我想创建一个扩展的类std::string
,(我知道不推荐,但为了讨论它只是承担它),并重载+=
,+
运算符.-Weffc ++给了我一个警告,因为它std::string
有一个非虚拟析构函数,但是如果子类没有成员并且不需要在它的析构函数中做任何事情,这是否重要?
FYI +=
重载是进行正确的文件路径格式化,因此可以使用路径类,如:
class path : public std::string {
//... overload, +=, +
//... add last_path_component, remove_path_component, ext, etc...
};
path foo = "/some/file/path";
foo = foo + "filename.txt";
std::string s = foo; //easy assignment to std::string
some_function_taking_std_string (foo); //easy implicit conversion
//and so on...
Run Code Online (Sandbox Code Playgroud)
我只是想确保有人这样做:
path* foo = new path();
std::string* bar = foo;
delete bar;
Run Code Online (Sandbox Code Playgroud)
不会导致内存分配问题?
GMa*_*ckG 13
不,从没有虚拟析构函数的类公开继承是不安全的,因为如果通过基类删除派生,则输入未定义的行为.派生类的定义是无关紧要的(数据成员与否等):
§5.3.5/ 3:在第一个备选(删除对象)中,如果操作数的静态类型与其动态类型不同,则静态类型应为操作数的动态类型的基类,静态类型应具有虚析构函数或行为未定义. (强调我的.)
代码中的这两个示例都会导致未定义的行为.您可以非公开地继承,但这显然会破坏使用该类然后扩展它的目的.(因为不再可能通过基指针删除它.)
这是(一个原因*)为什么你不应该继承标准库类.将最好的解决办法是将它与自由的功能扩展.事实上,即使你可以,你也应该更喜欢自由功能.
*另一个原因是:你真的想用新的字符串类替换所有的字符串用法,只是为了获得一些功能吗?这是很多不必要的工作.
所以每个人都说你不能这样做 - 它会导致不确定的行为.但是在某些情况下它是安全的.如果您从不动态创建类的实例,那么您应该没问题.(即没有新的电话)
也就是说,这通常被认为是一件坏事,因为有人可能会尝试在以后某个时候创建一个多态.(你可能可以通过私有的未实现的运算符来防止这种情况,但我不确定.)
我有两个例子,我不讨厌从具有非虚拟析构函数的类派生.第一个是使用临时创造语法糖...这是一个人为的例子.
class MyList : public std::vector<int>
{
public:
MyList operator<<(int i) const
{
MyList retval(*this);
retval.push_back(i);
return retval;
}
private:
// Prevent heap allocation
void * operator new (size_t);
void * operator new[] (size_t);
void operator delete (void *);
void operator delete[] (void*);
};
void do_somthing_with_a_vec( std::vector<int> v );
void do_somthing_with_a_const_vec_ref( const std::vector<int> &v );
int main()
{
// I think this slices correctly ..
// if it doesn't compile you might need to add a
// conversion operator to MyList
std::vector<int> v = MyList()<<1<<2<<3<<4;
// This will slice to a vector correctly.
do_something_with_a_vec( MyList()<<1<<2<<3<<4 );
// This will pass a const ref - which will be OK too.
do_something_with_a_const_vec_ref( MyList()<<1<<2<<3<<4 );
//This will not compile as MyList::operator new is private
MyList * ptr = new MyList();
}
Run Code Online (Sandbox Code Playgroud)
我能想到的另一个有效用法来自于C++中缺少模板typedef.这是你如何使用它.
// Assume this is in code we cant control
template<typename T1, typename T2 >
class ComplicatedClass
{
...
};
// Now in our code we want TrivialClass = ComplicatedClass<int,int>
// Normal typedef is OK
typedef ComplicatedClass<int,int> TrivialClass;
// Next we want to be able to do SimpleClass<T> = ComplicatedClass<T,T>
// But this doesn't compile
template<typename T>
typedef CompilicatedClass<T,T> SimpleClass;
// So instead we can do this -
// so long as it is not used polymorphically if
// ComplicatedClass doesn't have a virtual destructor we are OK.
template<typename T>
class SimpleClass : public ComplicatedClass<T,T>
{
// Need to add the constructors we want here :(
// ...
private:
// Prevent heap allocation
void * operator new (size_t);
void * operator new[] (size_t);
void operator delete (void *);
void operator delete[] (void*);
}
Run Code Online (Sandbox Code Playgroud)
下面是一个更具体的例子.您希望将std :: map与自定义分配器一起用于许多不同类型,但您不希望不可维护
std::map<K,V, std::less<K>, MyAlloc<K,V> >
Run Code Online (Sandbox Code Playgroud)
通过你的代码乱七八糟.
template<typename K, typename V>
class CustomAllocMap : public std::map< K,V, std::less<K>, MyAlloc<K,V> >
{
...
private:
// Prevent heap allocation
void * operator new (size_t);
void * operator new[] (size_t);
void operator delete (void *);
void operator delete[] (void*);
};
MyCustomAllocMap<K,V> map;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4253 次 |
最近记录: |