我在堆上分配对象,在某些情况下我将它们组合成一个新对象(我的Foo类主要包含2-3个STL容器)。 (另一种方法是使用副本,但我想这样效率会降低。)
这些操作可能会失败,因此可能会抛出异常。 除非我在抛出异常时释放动态内存,否则我将发生内存泄漏。
在这种情况下auto_ptr / unique_ptr会有意义吗? 我猜是因为Combine是一个“接收器”,但如果我想在调用Combine后使用f1和f2怎么办?
谢谢!
这是我的代码:
Foo* MakeFoo( )
{
Foo* foo = 0;
Foo* f1 = SimpleFoo( );
if( f1 )
{
Foo* f2 = SimpleFoo( );
if( f2 )
{
Foo* combined = Combine( f1, f2 );
delete f2;
delete f1;
}
else
foo = f1;
}
delete foo;
}
Foo* SimpleFoo( )
{
Foo* f = 0;
if( something )
{
f = new Foo;
if( somethingElse )
throw std::runtime_error( "Error" ); // Memory leak
}
return f;
}
Foo* Combine( const Foo* f1, const Foo* f2 )
{
assert( f1 );
assert( f2 );
// Memory leak in MakeFoo( )
if( something )
throw std::runtime_error( "Error" );
Foo* foo = new Foo;
// Maybe one could also simply modify f1
foo->Add( *f1 );
foo->Add( *f2 );
return foo;
}
答案 0 :(得分:2)
unique_ptr可以帮助你进行内存管理,但是除非你在Foo :: Add中将容器内置移动支持,否则你会想要使用shared_ptr,因为你无法复制unique_ptr的内容只移动所有权它
如果你的stl有unique_ptr和shared_ptr,你可能不应该使用auto_ptr。
shared_ptr的typedef也会清除一些代码。
答案 1 :(得分:1)
是的,unique_ptr在这里有意义。它为您处理内存管理,RAII。如果你想在调用之后使用这两个对象,它将在调用之前初始化并在调用Combine的范围之外创建。
答案 2 :(得分:1)
auto_ptr / unique_ptr会有意义吗? 在这种情况下?
是的,可以使用auto_ptr。它将确保不会发生内存泄漏。
但如果我想使用f1和f2怎么办? 在召集Combine之后?
您可以将原始指针传递给组合函数。 示例代码如下所示。
auto_ptr<Foo> f1 = auto_ptr<Foo>(new Foo);
auto_ptr<Foo> f2 = auto_ptr<Foo>(new Foo);
Foo* combined = Combine( f1.get(), f2.get() );
这样,指针的所有权不会转移到组合功能。 因此,你也可以在结合函数后使用f1和f2。
另外,请确保在MakeFoo函数中添加一个catch来捕获Combine函数抛出的异常。
答案 3 :(得分:1)
这个答案将假设您在return foo
结束时表示MakeFoo()
。我的第一选择是重构,以便不使用如此多的动态分配:
Foo *MakeFoo(){
if(!something)
return 0;
return Combine(SimpleFoo(), SimpleFoo());
}
Foo SimpleFoo(){
Foo foo;
if (something2) // hopefully related to foo. Otherwise, put this condition in MakeFoo
throw std::runtime_error("Error");
return foo;
}
Foo *Combine(const Foo &f1, const Foo &f2){
if (something3)
throw std::runtime_error("Error");
Foo *combination = new Foo;
combination->add(f1);
combination->add(f2);
return combination;
}
如果这不是你的选择,我会在'03:
中写下这样的内容Foo *MakeFoo(){
auto_ptr<Foo> f1 (SimpleFoo());
if (!f1.get())
return 0;
auto_ptr<Foo> f2> (SimpleFoo());
if (!f2.get())
return f1.release();
Foo *combined = Combine(f1.get(), f2.get());
f1.release();
f2.release();
return combined;
}
Foo *SimpleFoo(){
if (!something)
return 0;
auto_ptr<Foo> f (new Foo);
if (somethingHopefullyRelatedToF)
throw std::runtime_error("Error");
return f.release();
}
unique_ptr
可以相同地使用。 shared_ptr
也是一个非常广泛的锤子,但仍然可以解决这个问题。我确信上面的例子并不适合你的情况,但希望他们能给你适合你问题的想法。
答案 4 :(得分:0)
我修改了Combine并选择了你的答案组合来解决这个问题。 代码更短,更容易阅读。 我对此非常满意,谢谢大家!
typedef std::auto_ptr<Foo> A_Foo;
A_Foo MakeFoo( )
{
A_Foo foo = SimpleFoo( );
if( foo.get( ) )
{
A_Foo f2 = SimpleFoo( );
if( f2.get( ) )
Combine( *foo, *f2 );
}
return foo;
}
A_Foo SimpleFoo( )
{
if( something )
{
A_Foo f( new Foo );
if( somethingElse )
throw std::runtime_error( "Error" );
return f;
}
else
return A_Foo( );
}
void Combine( Foo& f1, const Foo& f2 )
{
if( something )
throw std::runtime_error( "Error" );
f1.Add( f2 );
}