裸指针的替换/重构

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_ptrstd::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)

pro*_*-fh 5

您可以使用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)

当然,之后您不能使用您的basePtrderivedPtr变量,因为它们不再拥有这些对象。

另一种方法是使用临时文件:

 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 以防止切片,但我们离最初的问题还很远。