可以说我有类似以下内容:
class A { virtual void g() = 0 }
class B : public A { virtual void g() { ... } }
class C : public A { virtual void g() { ... } }
... f(bool x)
{
if (x) { return B(); } else { return C(); }
}
bool get_boolean();
int main()
{
bool b = get_boolean();
... x = f(b);
x.g();
}
Run Code Online (Sandbox Code Playgroud)
无论如何,在没有调用的情况下执行类似上面的操作new,即仅在堆栈上?
避免动态分配的一种简单方法是使用静态分配,这与动态分配大致相反.然而,必须小心地完成它,因为即使使用非线程程序,也可能无意中陷入这样的情况:代码的两个或更多部分都认为它们"拥有"某些静态分配的对象.更糟糕的是,这些本质上的全局变量(即使伪装成单身人士,或者在下面的代码中作为本地静态)本质上也可以作为意大利面通信的中心枢纽,其中混乱诱导信息在您无法想象的地方之间自由传播,完全不在你的控制.
所以,静态分配方案有一些缺点...... :-)
但是,让我们从那里开始:
// Using static allocation.
#include <iostream>
using namespace std;
struct A { virtual void g() = 0; };
struct B : A { virtual void g() override { wcout << "A\n"; } };
struct C : A { virtual void g() override { wcout << "B\n"; } };
A& f( bool const x )
{
static B theB;
static C theC;
if( x ) { theB = B(); return theB; } else { theC = C(); return theC; }
}
bool get_boolean() { return false; }
int main()
{
bool const b = get_boolean();
A& x = f( b );
x.g();
}
Run Code Online (Sandbox Code Playgroud)
为了避免静态分配方案的错误所有权缺陷,您可以使用C++ 自动分配在堆栈上提供存储(C++自动分配是按定义的堆栈,LIFO分配方案).但这意味着将存储传递给函数.然后,该函数可以返回对相关对象的引用:
// Using automatic storage (the stack)
#include <iostream>
using namespace std;
struct A { virtual void g() = 0; };
struct B : A { virtual void g() override { wcout << "A\n"; } };
struct C : A { virtual void g() override { wcout << "B\n"; } };
A& f( bool const x, B& b, C& c )
{
if( x ) { b = B(); return b; } else { c = C(); return c; }
}
bool get_boolean() { return false; }
int main()
{
bool const b = get_boolean();
B objBStorage;
C objCStorage;
A& x = f( b, objBStorage, objCStorage );
x.g();
}
Run Code Online (Sandbox Code Playgroud)
但即使我们选择忽略诸如带有副作用的构造等问题,即当我们轻率地假设类B并且C被设计为与这样的方案一起工作时,上述浪费存储.如果B和C实例很大,那么可以考虑使用C++的工具在预先存在的存储中构造对象,称为placement new.由于内存对齐问题,在C++ 03中正确执行有点困难,但C++ 11提供了更好的支持,如下所示:
#include <iostream>
#include <memory> // unique_ptr
#include <new> // new
#include <type_traits> // aligned_storage
using namespace std;
typedef unsigned char Byte;
struct A { virtual void g() = 0; };
struct B : A { virtual void g() override { wcout << "A\n"; } };
struct C : A { virtual void g() override { wcout << "B\n"; } };
A* f( bool const x, void* storage )
{
return (x? static_cast<A*>( ::new( storage ) B() ) : ::new( storage ) C());
}
bool get_boolean() { return false; }
void destroyA( A* p ) { p->~A(); }
int main()
{
enum{ enoughBytes =
(sizeof( B ) > sizeof( C ))? sizeof( B ) : sizeof( C ) };
typedef aligned_storage< enoughBytes >::type StorageForBOrC;
bool const b = get_boolean();
StorageForBOrC storage;
A* const pX = f( b, &storage );
unique_ptr<A, void(*)(A*)> const cleanup( pX, destroyA );
pX->g();
}
Run Code Online (Sandbox Code Playgroud)
现在,我会选择上述哪一项?
我会选择严格限制但简单的即时静态分配,还是选择内存浪费自动分配,或者......优化但有些复杂的就地对象构造?
答案是,我不会选择任何一个!
我不会专注于微观效率,而是专注于清晰度和正确性,因此只需要动态分配的性能.为了正确,我会使用智能指针来表示功能结果.如果这真的让事情变得迟钝,我或许会考虑使用专用的小对象分配器.
总之,不要担心小东西!:-)
| 归档时间: |
|
| 查看次数: |
2019 次 |
| 最近记录: |