Vin*_*ier 1 c++ smart-pointers
我想在类继承情况下替换传统的裸指针用法。
我的意思的例子:
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Base
{
public:
void doBaseStuff ()
{
cout << "base stuff\n";
}
};
class Derived:public Base
{
public:
void doDerivedStuff ()
{
cout << "derived stuff\n";
}
};
int main ()
{
// vector to hold pointers
vector < Base * >baseCollection;
// generate pointers
Derived *derivedPtr = new Derived;
Base* basePtr = new Base;
// use derived pointer for something
derivedPtr->doDerivedStuff ();
// fill vector with pointers
baseCollection.push_back (basePtr);
baseCollection.push_back (derivedPtr);
// iterate some 'interface' method
for (auto & element:baseCollection)
{
element->doBaseStuff ();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如下所示的重构是正确的方法吗?我使用 C++17。std::unique_ptr而std::shared_ptr不是在这种情况下不会编译(行:)baseCollection.push_back(derivedPtr);。
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
// sample classes
class Base
{
public:
void doBaseStuff ()
{
cout << "base stuff\n";
}
};
class Derived:public Base
{
public:
void doDerivedStuff ()
{
cout << "derived stuff\n";
}
};
int main ()
{
// vector to hold pointers
vector<shared_ptr<Base>> baseCollection;
// generate pointers
shared_ptr<Base> basePtr = make_shared<Base>();
shared_ptr<Derived> derivedPtr = make_shared<Derived>();
// use derived pointer for something
derivedPtr->doDerivedStuff();
// fill vector with pointers
baseCollection.push_back(basePtr);
baseCollection.push_back(derivedPtr); // implicit cast from shared_ptr<Derived> to shared_ptr<Base> !?
// iterate some 'interface' method
for(auto& element : baseCollection)
{
element->doBaseStuff();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,两种情况下的输出如下:
derived stuff
base stuff
base stuff
Run Code Online (Sandbox Code Playgroud)
您可以使用std::unique_ptr代替std::shared_ptr(确实推荐使用,因为所有权在您的应用程序中明确处理,而不是未指定给某种垃圾收集器),但是您必须将它们移动到向量中才能传输(唯一)所有权。
vector<unique_ptr<Base>> baseCollection;
// generate pointers
unique_ptr<Base> basePtr = make_unique<Base>();
unique_ptr<Derived> derivedPtr = make_unique<Derived>();
// use derived pointer for something
derivedPtr->doDerivedStuff();
// fill vector with pointers
baseCollection.push_back(std::move(basePtr));
baseCollection.push_back(std::move(derivedPtr));
Run Code Online (Sandbox Code Playgroud)
当然,之后您不能使用您的basePtr和derivedPtr变量,因为它们不再拥有这些对象。
另一种方法是使用临时文件:
baseCollection.push_back(make_unique<Base>());
baseCollection.push_back(make_unique<Derived>());
Run Code Online (Sandbox Code Playgroud)
请注意,在处理unique_ptrs时,您仍然可以使用原始指针(使用.get()成员函数),但含义不同:我知道一个由其他人拥有的对象(unique_ptr此处为a )。
并且如评论中所述,为了确保正确析构,Base应该是virtual ~Base()=default;析构函数 of baseCollection,因为析构函数 of不知道Base指针实际上指向 a Derived(可能大小不一样,需要动态调度)。这与unique_ptr也无关shared_ptr;原始指针存在问题。更进一步,由于我们有多态类型,我们应该禁用 ( =delete) copy/move-constructors/assign 以防止切片,但我们离最初的问题还很远。