设计困境..... [英] Design Woes.....

查看:45
本文介绍了设计困境.....的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



当我看到Andrei Alexandrescu的帖子时,我有点松了一口气

突出了我面临的类似问题:

所以这就是Andrei Alexandrescu写的:

[开始]

我编写一个通用对象工厂。显然,工厂有一个像CreateObject这样的函数返回一个新分配的对象。


问题是,我打破了一个重要的编码标准:永远不会返回

指向新分配的内存。永远不要通过返回

指针来通过所有权。永远不要做strdup做的事。永远不会意味着永远。

[/ stop]


我怀疑我应该关注打破编码标准但是

我还没到那么远。为简单起见,我会突出显示这些东西 -

,根据以下来源 - 这很重要。所以现在考虑:


#ifndef FACTORY_H

#define FACTORY_H

#include< map>

#include< string>


struct stream;

class source //

{

public:

virtual bool load_from_stream(stream& ds)= 0;

virtual void execute()= 0;

}; < br $>
////////////////////////////// * //////

//工厂

class ClassFactory

{

public:

虚拟源* create()= 0 ;

virtual std :: string name()= 0;

};


template< class T>

class FactoryWrapper

:public ClassFactory {

public:

virtual source * create() {

返回T :: create();

}

virtual std :: string name(){

返回T :: name();

}

};


类工厂

{

std :: map< std :: string,ClassFactory *> _facts;

public:

void registerFactory(ClassFactory * factory);

source * create(const stream& ds);

};


#endif;


struct test

:公共资源

{

static std :: string name(){

return" test";

}

静态测试* create(){返回新测试();}

};


//现在我们准备好了。 main.cpp

class testFact {

FactoryWrapper< test> class1Factory;

工厂工厂;


// test m_test; //想要将ptest复制到m_test或..

public:

testFact(){

factories.registerFactory(& cla * ss1Factory);

}


无效记录()

{

//使用ptest或某些变体

// ptest

}


void get_data()

{

char buffer [4096] = {" testing" };

size_t len = sizeof buffer / sizeof * buffer;

data_stream st(buffer,len);

if(st)

{

test * ptest =

static_cast< test *>(factories.c * reate(st));

if(!ptest){

//用ptest做一些

删除ptest;

}

}

}

};


每次在get_data中创建的调用都会导致对内存的调用

必须被释放。麻烦的是:我需要在别处使用ptest对象。

例如在记录成员函数中。也就是说,如何创建对象的本地副本以供其他地方使用?


如果我将ptest复制到另一个类型为test的对象,这是不安全的,因为

内存将被ptest释放。


话虽如此。为了满足编码标准,我怀疑

我可以将测试对象传递给create函数。我不太确定我会理解这个解决了什么,或者我完全理解如何实现这个目标。


提前致谢。


I was relieved somewhat when I saw a post by Andrei Alexandrescu
highlighting an similar issue I''m faced with:
So here''s what Andrei Alexandrescu wrote:
[start]
I code a generic object factory. Obviously, the factory has a member
function like CreateObject that returns a newly allocated object.

The problem is, I break an important coding standard: never return
pointers to newly allocated memory. Never pass ownership by returning
pointers. Never do what strdup does. And never means never.
[/stop]

I suspect I should be concerned about breaking the coding standards but
I haven''t got that far yet. For simplicity, I''ll highlight the stuff -
per the source below - that counts. So now consider:

#ifndef FACTORY_H
#define FACTORY_H
# include <map>
# include <string>

struct stream;
class source //
{
public:
virtual bool load_from_stream(stream& ds) = 0;
virtual void execute() = 0;
};
//////////////////////////////*//////
// factory
class ClassFactory
{
public:
virtual source* create()=0;
virtual std::string name()=0;
};

template < class T >
class FactoryWrapper
: public ClassFactory {
public:
virtual source* create(){
return T::create();
}
virtual std::string name(){
return T::name();
}
};

class Factories
{
std::map<std::string, ClassFactory*> _facts;
public:
void registerFactory( ClassFactory* factory);
source* create(const stream& ds);
};

#endif;

struct test
: public source
{
static std::string name() {
return "test";
}
static test* create(){ return new test();}
};

// now we''re ready. main.cpp
class testFact {
FactoryWrapper<test> class1Factory;
Factories factories;

// test m_test; // would like to copy ptest to an m_test or ..
public:
testFact () {
factories.registerFactory(&cla*ss1Factory);
}

void record()
{
// use ptest or some variant
//ptest
}

void get_data()
{
char buffer[4096] = { "testing" };
size_t len = sizeof buffer / sizeof *buffer;
data_stream st (buffer, len);
if (st)
{
test *ptest =
static_cast<test*>(factories.c*reate(st));
if ( !ptest ) {
// do somethign with ptest
delete ptest;
}
}
}
};

Each call to create within get_data results in a call to memory that
must be freed. Trouble is: I need to use the ptest object elsewhere.
For instance within the record member function. That said, how does one
go about creating a local copy of the object for use elsewhere?

If I copy ptest to another object of type test, that''s unsafe since the
memory will be freed by ptest.

Having said that. In an attempt to ''meet'' coding standards, I suspect
I could pass a test object to the create function. I''m not so sure I
understand what this solves or I''m fully understanding how to achieve
this.

Thanks in advance.

推荐答案

ma740988写道:
ma740988 wrote:
问题是,我打破了一个重要的编码标准:永远不会返回指向新分配内存的指针。永远不要通过返回
指针来传递所有权。永远不要做strdup做的事。永远不会意味着永远。


有一个更全面的指南:每当你编码''新'时,立即

帐户''删除''。


影响你作为程序员的行为。当你键入它时,很快就输入

。它引出了你引用的规则,如果那个

接口的客户端可能还没有被写入,那么你就不能解释删除。

class ClassFactory
{
公开:
虚拟源* create()= 0;


你能否退回std :: auto_ptr<>?我以为他们可以自动升级并将
投入到派生类型的''源'中。

struct test:public source


我们可以在这里看到一个真实的测试用例,比如CPPUnit吗? ;-)

静态测试* create(){return new test();}
The problem is, I break an important coding standard: never return
pointers to newly allocated memory. Never pass ownership by returning
pointers. Never do what strdup does. And never means never.
There''s a more encompassing guideline: Each time you code ''new'', immediately
account for the ''delete''.

That affects your behavior as a programmer. When you type this, type that
too, very soon. And it leads to the rule you cite, if the client of that
interface might not be written yet, so you can''t account for the delete.
class ClassFactory
{
public:
virtual source* create()=0;
Can you return std::auto_ptr<>? I thought they could automatically up and
down cast themselves into derived types of ''source''.
struct test: public source
Could we see a real test case here, like from CPPUnit? ;-)
static test* create(){ return new test();}




对。现在也不能返回一个auto_ptr,类型协变与

基类'的类型?


另外看一下Boost shared_ptr 。


-

Phlip
http://www.c2.com/cgi/wiki?ZeekLand


|对。现在也不能返回一个auto_ptr,类型协变

和基类的类型?


到目前为止听起来像我''需要:

virtual std :: auto_ptr< source *> create()= 0;


我意识到auto_ptr方法有内置的语义可以做到
自动清理。从它的声音我会回顾你强调的两种方法



但这里是更重要的问题。返回的对象需要

可在其他地方使用。你怎么看待这个?再次。

使用get_data成员函数,创建一个ptest对象。我想

喜欢在多个地方保留本地副本 - 例如上面说明的

记录功能。

| Right. Now can''t this return an auto_ptr too, of a type covariant
with the base class''s type?

Thus far it sounds like I''ll need:
virtual std::auto_ptr<source*> create()=0;

I realize the auto_ptr approach has the built in semantics to do
automatic cleanup. From the sound of it I''ll review the two approaches
you highlighted.
but here''s the more important question. The returned object needs to
be available for use elsewhere. How do you approach this? Again.
Withiin the get_data member function, a ptest object is created. I''d
like to keep a local copy for use in multiple places - for instance the
record function illustrated above.




ma ****** @ pegasus .cc.ucf.edu 写道:
|对。现在不能再返回一个类型协变的auto_ptr和基类的类型吗?

到目前为止听起来像我需要的那样:
virtual std :: auto_ptr< source *>创建()= 0;


我认为它只是''std :: auto_ptr< source>''给你一个管理的

指向''源'的指针'对象。你可以使用auto_ptr对象作为

指针,或者你可以从中获取或释放指向对象(''source'')

。 />
我意识到auto_ptr方法有内置的语义来进行自动清理。从它的声音我会回顾你强调的两种方法。
但这里是更重要的问题。返回的对象需要可以在其他地方使用。你怎么看待这个?再次。
使用get_data成员函数,创建一个ptest对象。我希望保留一份本地副本以便在多个地方使用 - 例如上面说明的
记录功能。
| Right. Now can''t this return an auto_ptr too, of a type covariant
with the base class''s type?

Thus far it sounds like I''ll need:
virtual std::auto_ptr<source*> create()=0;
I think it''s just ''std::auto_ptr<source>'' which gives you a managed
pointer to a ''source'' object. You can use the auto_ptr object as a
pointer, or you can get or release the pointed-to object (the ''source'')
from it.
I realize the auto_ptr approach has the built in semantics to do
automatic cleanup. From the sound of it I''ll review the two approaches
you highlighted.
but here''s the more important question. The returned object needs to
be available for use elsewhere. How do you approach this? Again.
Withiin the get_data member function, a ptest object is created. I''d
like to keep a local copy for use in multiple places - for instance the
record function illustrated above.




自从''testFact''类没有维护指向内存的指针

由''get_data''分配,你必须将参数传递给''记录''

任何事件。在这种情况下,您可以将可修改的引用传递给

''std :: auto_ptr< source>''。因此,''record''能够拥有该对象或

not(因为参数是可修改的)。


但是,如果你要去通过''get_data''保留分配内存的本地副本

,整个auto_ptr参数变得毫无意义,因为你的
''testFact''对象可以管理自己的内存。


顺便提一下,工厂(协议)也提供''deallocate''和''deleteObject''方法是个好主意。这样,工厂实现可以从

堆以外的地方(例如,来自池或缓冲区)自由分配内存。但是,你不能再使用''auto_ptr''因为你不能将工厂与它联系起来;它只有

知道新/删除。这是另一天的另一个问题...


/ david



Since the ''testFact'' class does not maintain a pointer to memory
allocated by ''get_data'', you have to pass a parameter to ''record'' in
any event. In this case, you can pass a modifiable reference to
''std::auto_ptr<source>''. Thus, ''record'' is able to own the object or
not (since the parameter is modifiable).

However, if you are going to keep a local copy of the memory allocated
by ''get_data'', the whole auto_ptr argument becomes moot because your
''testFact'' object can manage its own memory.

Incidentally, it is a good idea for a factory (protocol) to also
provide ''deallocate'' and ''deleteObject'' methods. This way, factory
implementations are free to allocate memory from places other than the
heap (for example, from pools or buffers). However, you can no longer
use ''auto_ptr'' because you cannot associate a factory with it; it only
knows about new/delete. That is another problem for another day...

/david


这篇关于设计困境.....的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆