Replacing/refactoring 个裸指针
Replacing/refactoring of naked pointers
我想在 class 继承情况下替换传统的裸指针用法。
我的意思的例子:
#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;
}
如下所示的重构方法是否正确?我使用 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;
}
正如预期的那样,两种情况下的输出如下:
derived stuff
base stuff
base stuff
您可以使用 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));
当然,之后您不能再使用 basePtr
和 derivedPtr
变量,因为它们不再拥有这些对象。
另一种方法是使用临时对象:
baseCollection.push_back(make_unique<Base>());
baseCollection.push_back(make_unique<Derived>());
请注意,在处理 unique_ptr
时,您仍然可以使用原始指针(使用 .get()
成员函数)但含义不同:我 知道 由其他人拥有 的对象(此处为 unique_ptr
)。
并且如评论中所述,为了确保正确销毁,Base
的析构函数应为 virtual ~Base()=default;
,因为 baseCollection
的析构函数不知道 Base
指针实际上指向一个 Derived
(可能大小不一样,需要动态调度)。这与 unique_ptr
和 shared_ptr
无关;原始指针存在问题。
更进一步,由于我们有多态类型,我们应该禁用 (=delete
) copy/move-constructors/assign 以防止切片,但我们离最初的问题还很远。
Is refactoring this as shown below the correct way?
重构程序的行为与第一个不同。第一个程序会泄漏内存,而重构后的程序不会。只要是故意的,这当然通常是一件好事。
I use C++17. std::unique_ptr instead of std::shared_ptr won't compile in this case.
那是因为您复制了指针,而唯一指针是不可复制的。您可以改为移动指针。但是,指向基的唯一指针还有一个共享指针没有的问题:如果通过指向基的指针删除派生对象,并且基的析构函数不是虚拟的,那么程序的行为将是未定义的。这可以通过将基础的析构函数设为虚拟来轻松解决。
因此,只要不复制指针,并且将析构函数设为虚拟,就无需支付共享所有权的开销。
我想在 class 继承情况下替换传统的裸指针用法。
我的意思的例子:
#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;
}
如下所示的重构方法是否正确?我使用 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;
}
正如预期的那样,两种情况下的输出如下:
derived stuff
base stuff
base stuff
您可以使用 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));
当然,之后您不能再使用 basePtr
和 derivedPtr
变量,因为它们不再拥有这些对象。
另一种方法是使用临时对象:
baseCollection.push_back(make_unique<Base>());
baseCollection.push_back(make_unique<Derived>());
请注意,在处理 unique_ptr
时,您仍然可以使用原始指针(使用 .get()
成员函数)但含义不同:我 知道 由其他人拥有 的对象(此处为 unique_ptr
)。
并且如评论中所述,为了确保正确销毁,Base
的析构函数应为 virtual ~Base()=default;
,因为 baseCollection
的析构函数不知道 Base
指针实际上指向一个 Derived
(可能大小不一样,需要动态调度)。这与 unique_ptr
和 shared_ptr
无关;原始指针存在问题。
更进一步,由于我们有多态类型,我们应该禁用 (=delete
) copy/move-constructors/assign 以防止切片,但我们离最初的问题还很远。
Is refactoring this as shown below the correct way?
重构程序的行为与第一个不同。第一个程序会泄漏内存,而重构后的程序不会。只要是故意的,这当然通常是一件好事。
I use C++17. std::unique_ptr instead of std::shared_ptr won't compile in this case.
那是因为您复制了指针,而唯一指针是不可复制的。您可以改为移动指针。但是,指向基的唯一指针还有一个共享指针没有的问题:如果通过指向基的指针删除派生对象,并且基的析构函数不是虚拟的,那么程序的行为将是未定义的。这可以通过将基础的析构函数设为虚拟来轻松解决。
因此,只要不复制指针,并且将析构函数设为虚拟,就无需支付共享所有权的开销。