我有一个我正在创建的模板类,我需要一个方法来返回该类的对象并分配它。我有一个方法,它接收2个对象,创建一个新对象,并返回它,以及赋值运算符的重载,以正确复制成员。
我试过这两种方法(两种方法都是静态的)。
方法1:有效,但这不是一种不好的做法吗?
template <class T>
MyClass<T>* MyClass<T>::MyFunction(const MyClass& a, const MyClass& b)
{
MyClass<T> *newObject= new MyClass<T>(a.member, b.member2);
//...do stuff to the object
return newObject;
}
方法2:不起作用,但这不是一个更好的思路吗?
template <class T>
MyClass<T> MyClass<T>::MyFunction(const MyClass& a, const MyClass& b)
{
MyClass<T> newObject(a.member, b.member2);
//...do stuff to the object
return newObject;
}
我对方法1的恐惧是我在堆中创建一个新对象而不是破坏它。我将其所有成员分配给另一个MyClass实例,但如果我第二次执行该操作,第一个实例会发生什么?我在堆栈上创建的第一个“新”对象是否只是坐在那里?
我对方法2的问题是在调用赋值操作重载之前,对象超出了范围。我查看了复制构造函数并移动构造函数。不幸的是,我没有看到在这种情况下被召唤的人(可能是这里缺乏经验)。
完成后,以下是相关代码的其余部分。
template <class T>
void MyClass<T>::operator = (const MyClass& b)
{
if (this == &b) { return; }
DeleteData();
//just calls the same member removal operation as the destructor
//to clear everything out to receive new data
//...simple member copying stuff
}
template<class T>
inline void MyClass<T>::DeleteData()
{
//call delete on members which need to be deleted manually
}
template <class T>
MyClass<T>::~MyClass()
{
DeleteData();
}
template <class T>
MyClass<T>::MyClass(const T member, const T member2)
{
//member initialization operations
}
示例用法:
MyClass<T> myObj1(member1, member 2);
MyClass<T> myObj2(member1, member 2);
MyClass<T> myObj3 = *(MyClass<T>::MyFunction(myObj1, myObj2));
TL; DR问题:
在函数内使用new
返回class*
而不是class
时,创建的对象在不再有任何引用时会被销毁吗?
如果没有,返回在方法中创建的对象的最佳做法是什么?
如果是这样,这种方法是不好的做法吗?
我很抱歉,如果之前已经回答了这个问题,我对C ++的新感觉已经足够我以前的研究并没有给我一个满意的答案,可能是因为我不知道我不知道的事情。
实施解决方案: (我还添加了一个拷贝构造函数。没有它,这个解决方案仍然适用于问题的范围,但是有一些项目超出了这个问题的范围,由一个修复。希望未来有人可能会发现这个信息有用)
//this is a static function of MyClass
template <class T>
std::unique_ptr<MyClass<T>> MyClass<T>::MyFunction(const MyClass& a, const MyClass& b)
{
std::unique_ptr<MyClass<T>> newObj = std::make_unique<MyClass<T>>(a.member, b.member2);
//...Be the factory...
return newObj ;
}
int main()
{
MyClass<T> myObj1(member1, member 2);
MyClass<T> myObj2(member1, member 2);
MyClass<T> myObj3 = *(MyClass<T>::MyFunction(myObj1, myObj2));
}
答案 0 :(得分:3)
在函数内使用
new
返回class*
而不是class
时,创建的对象在不再有任何引用时会被销毁吗?
不是。传递给new
的任何内容都必须明确deleted
,或传递给承担其所有权的容器(例如unique_ptr
)。
如果是这样,这种方法是不好的做法吗?
这取决于,但通常是肯定的,不鼓励返回和处理原始指针,因为它容易发生内存泄漏。您上面的代码确实泄漏了(如您所述)。
如果没有,返回在方法中创建的对象的最佳做法是什么?
这取决于。如果您不介意复制,或者您的对象已定义移动语义,您可以返回方法2中的具体对象,并希望编译器执行return value optimization。
如果您介意复制,请考虑某种returning a smart pointer:
template <class T>
std::unique_ptr<MyClass<T>> MyClass<T>::MyFunction(const MyClass& a, const MyClass& b)
{
auto newObject = std::unique_ptr<MyClass<T> {new MyClass<T>(a.member, b.member2)};
//...do stuff to the object
return newObject;
}
答案 1 :(得分:2)
这个怎么样:
template <class T>
std::shared_ptr<MyClass<T>> MyClass<T>::MyFunction(const MyClass& a, const MyClass& b)
{
auto newObject = std::make_shared<MyClass<T>>(MyClass<T>(a.member, b.member2));
//...do stuff to the object
return newObject;
}
如果您考虑返回指针,这是在现代C ++中实现它的正确方法。共享指针将为您清除所有内容,并且您不会传递副本。假设您不想使用移动构造函数。
编辑:
由于人们在评论中批评了shared_ptr
,因为它用火箭筒杀死了一只苍蝇(我同意),我也提供unique_ptr
。请注意unique_ptr
是一个必须移动而不是复制的唯一对象。
template <class T>
std::unique_ptr<MyClass<T>> MyClass<T>::MyFunction(const MyClass& a, const MyClass& b)
{
auto newObject = std::unique_ptr<MyClass<T>>(new MyClass<T>(a.member, b.member2));
//...do stuff to the object
return newObject;
}
PS:请注意,我没有使用make_unique
(而不是make_shared
)。这是因为make_unique
是C ++ 14,而不是C ++ 11。
答案 2 :(得分:0)
在C ++代码中,通常在任何地方传递指针是很常见的。一般来说,最好让指针的创建者也将其销毁。但是将指针的所有权传递给其他人也是可以接受的,让他们负责维护和销毁指针。
在你看来你的方法只不过是工厂方法的情况下尤其如此。将工厂方法视为与构造函数相同是完全可以的。而那个负责创造 - 并负责摧毁 - 指针的人。
如果您不太关心最佳做法,只是希望它对内存安全,那么您可以在std::shared_pointer
中使用#include <memory>
。这些行为有点像垃圾收集者。您可以像使用普通指针一样使用它们。但是一旦对它的最后一次引用超出范围,它就会为你删除底层指针。