Newsgroup: it.comp.lang.c++
Titolo: Oggetto *solo* dinamico

Ciao =)
Sono alle prime armi del c++, e nel tentativo quasi disperato di impararlo, 
mi sono imbattuto in un semi-dilemma. Per mia curiosità, e per uno sfizio di 
omogeneità di codice (se così si può dire), volevo sapere se è possibile 
fare in modo che un oggetto possa essere allocato *solo* dinamicamente (per 
intenderci, nello heap, con new), un po' come fa la VCL della Borland. 
Ovvero, se è possibile a compile-time avere un errore nel caso in cui si 
voglia allocare un oggetto sullo stack. Pensavo di nascondere il 
costruttore, e fare un overloading di new. Il fatto è che new alloca solo lo 
spazio, e poi comunque chiama un costruttore... cosa dovrei fare, una 
allocazione interna, come per i singleton ? Oppure c'è un modo più elegante ?
Questa "fisima" mi è venuta mentre cercavo il modo migliore (purtroppo sono 
un amante del "modo migliore", cosa che mi blocca continuamente...) per 
scrivere un albero binario. Forse sbaglio approccio ? Infine (dato che ormai 
ho rotto le scatole al gruppo andrò fino in fondo =P) io utilizzo un albero 
perchè devo ordinare un'espressione matematica (con la stessa sintassi di 
MatLab, per intenderci). L'albero binario è una buona scelta, oppure risulta 
più comoda una pila, rimaneggiando l'espressione in notazione polacca 
inversa ? Vi prego, scioglietemi questi dubbi che mi bloccano, impedendomi 
di scrivere del codice !!!
'sera lietissima, Marco

 questi dubbi che mi bloccano, impedendomi di scrivere del codice !!!
Uhm... non ho idea di cosa tu intenda con "ordinare un'espressione 
matematica", dato anche che (mea culpa, mea culpa, mea grandissima 
culpa) non ho mai usato MatLab.
Anyway, prima di reinventare la ruota: guarda attentamente la parte dei 
contenitori della libreria standard, magari c'e' gia' quel che tu stai 
scrivendo... santa ereditarieta'!
-- 
/**
  * Mattia Belletti - Undergraduate student @ 
cs.unibo.it
  * ICQ: 33292311   - email: 
mbel...@cs.unibo.it
  * IRC: BluShine   - site(s): 
http://cs.unibo.it/~mbellett
  * Linux registered user 299762 @ Linux registered machine 213003
  */

 scrivendo... santa ereditarieta'!
enno... i container della stl non hanno distruttore virtuale! santo
incapsulamento casomai ;)
sbirish.

 incapsulamento casomai ;)
Ah, questo non me lo ricordavo.
Pazienza! :)


 di scrivere del codice !!!
Dipende dalla complessita' delle espressioni che manipoli. La strada
piu' potente, che pero' e' anche complessa, e' quella di
rappresentarle su un albero dove i nodi sono le operazioni e le foglie
i valori espliciti e di calcolarle navigando l'albero.
Ciao,
Nicola

 costruttore, e fare un overloading di new.
Un'alternativa a quello che ti hanno suggerito (factory method) č rendere 
privato il distruttore e fornire un apposito metodo che distrugga 
l'instanza ('delete this').
Max

Rispondo a me stesso per rispondere a tutti: grazie mille, dovrei aver 
risolto... continuerò a divertirmi con gli alberi per un po' =P
'sera lietissima, Marco

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
sbirish wrote:

Embe ? visto che non lo hanno cosa vuol dire che non si possono
derivare? Basta non allocare memoria dinamica.
G.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (MingW32)
Comment: Using GnuPG with Thunderbird - 
http://enigmail.mozdev.org
iD8DBQE/znx87UpzwH2SGd4RAsdjAJsEfay0OPMobYOO7B0fgDoTlzy4HQCdHD7U
CYdOmb+vvk9U/TgPvMy2MvI=
=puH1
-----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Mattia Belletti wrote:
| Markobre wrote:
| Mah, perche' ritieni corretto che uno possa allocarlo sollo nell'heap?
| Cosa ti ha fatto lo stack di male? :D
| Cmq, quel che farei io, e' un pattern simile al singleton, chiamato
| "Factory method" - e' uno dei piu' famosi. Ovvero una classe tipo:
|
| class Albero
| {
|   private:
|     Albero();
|   public:
|     static Albero* creaAlbero();
| };
Sei sicuro che basti ?
E il costruttore di copia che viene generato automaticamente, non credi
che crei istanze che non stanno sull'heap ?
Mettere il costruttore per default nella parte privata e' esagerato.
Basta mettere il distruttore nella parte protected, cosi' almeno la puoi
derivare, i problemi comunque non finiscono.....
G.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (MingW32)
Comment: Using GnuPG with Thunderbird - 
http://enigmail.mozdev.org
iD8DBQE/zn4D7UpzwH2SGd4RAoqWAJ9pF5ohfoDYggRznYNXKixkxXYiZQCeO7+8
vurt0Fi+OZbPqMaDwamIsPg=
=Ep5G
-----END PGP SIGNATURE-----

 derivare? Basta non allocare memoria dinamica.
enforzami che il container non venga cotruisto via new e dammi una buona
ragione per averlo fatto e ti do ragione.
sbirish-

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
sbirish wrote:
| On Thu, 04 Dec 2003 01:14:52 +0100, Gaetano Mendola wrote:
|
|
|>-----BEGIN PGP SIGNED MESSAGE-----
|>Hash: SHA1
|>
|>sbirish wrote:
|>
|>|>Anyway, prima di reinventare la ruota: guarda attentamente la parte dei
|>|>contenitori della libreria standard, magari c'e' gia' quel che tu stai
|>|>scrivendo... santa ereditarieta'!
|>| enno... i container della stl non hanno distruttore virtuale! santo
|>| incapsulamento casomai ;)
|>
|>Embe ? visto che non lo hanno cosa vuol dire che non si possono
|>derivare? Basta non allocare memoria dinamica.
|
|
| enforzami che il container non venga cotruisto via new e dammi una buona
| ragione per averlo fatto e ti do ragione.
Perche' se viene fatta con una new e la classe derivata non alloca
memoria dinamica che succede ?
Buona ragione, ti do un mio esempio pratico.
Ho una classe che si chiama NetList che deriva
da NetObject e da std::list<T>.
Questo per il fatto che NetObject mi da a disposizione
un meccanismo per ficcarlo direttamente dentro un socket,
il fatto che sia un std::list<T> mi garantisce poterlo
usare dentro l'algoritmo sort.
Ti sembra una motivazione valida ?
Gaetano
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (MingW32)
Comment: Using GnuPG with Thunderbird - 
http://enigmail.mozdev.org
iD8DBQE/zyDd7UpzwH2SGd4RAq8NAJ4zOVzRaRiHntC4Iv1ofcqStwaWQQCeLMxM
pRP/8epIjk+qnkgVmRi3SRM=
=YTon
-----END PGP SIGNATURE-----

 Ti sembra una motivazione valida ?
no per il motivo di cui sopra,
avrei scritto:
template <typename T, class Alloc = std::allocator<T> >
class NetList : public NetObject
{
   typedef std::vector<T,Alloc> Container;
   Container cont_;
 public:
   /* ... */
};
per dovere di cronaca...  
per std::sort servono dei random access iterarators,
che std::list non ti da.
-- 
Roberto Ferranti

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
sbirish wrote:
| il mio punto è che questa sia una chiara violazione del Liskov
| Substitution Principle, pessimo design da cui deriva la fragilità di cui
| sopra.
| <cite (parafrasato)>
|  FUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE CLASSES MUST BE ABLE TO
|  USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT .
| </cite>
|
| WeirdVector di conseguenza non può essere in relazione IS-A con
| std::vector
Se un oggetto e derivato da un altro in maniera publica
stanno in relazione IS-A e WeirdVector sta in relazione
IS-A con vector.
io posso scrivere  vec->push_back(3);
sto usando WeirdVector senza saperlo.
| spero nessuno si insulti rispondendo "ma io non uso mai un pointer alla
| base"
altrimenti a che servirebbe.
| avrei scritto:
|
|
| template <typename T, class Alloc = std::allocator<T> >
| class NetList : public NetObject
| {
|    typedef std::vector<T,Alloc> Container;
|    Container cont_;
|  public:
|    /* ... */
|
| };
|
| per dovere di cronaca...
| per std::sort servono dei random access iterarators,
| che std::list non ti da.
List era il primo container che mi e' venuto in mente
e sort il primo algoritmo.
Come uso poi NetList in una funzione con signature:
template <typename T>
void foo( const std::vector<T>& aVector) const;
Gaetano.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (MingW32)
Comment: Using GnuPG with Thunderbird - 
http://enigmail.mozdev.org
iD8DBQE/z5BX7UpzwH2SGd4RAp6yAKDLYeOG5MVXriSjMYhOk5JmgFj5EwCgjpIO
+svD+aesxy1H/Fw2S5o4O7Q=
=x1P9
-----END PGP SIGNATURE-----

 void foo( const std::vector<T>& aVector) const;
spiegami perché tale funzione( metodo a dire il vero vista la sign ) 
non prende due iterator invece che una const reference ad un vector<T> 
( come fanno tutti gli algorimiti in std:: boost:: & C ) ?
anche questo è un caso di cattivo design.
sbirish.

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
sbirish wrote:
| On Thu, 04 Dec 2003 20:52:14 +0100, Gaetano Mendola wrote:
|>io posso scrivere  vec->push_back(3);
|>sto usando WeirdVector senza saperlo.
|
|
| puoi farlo anche wrappando.
E siamo daccordo ma devo ridefinire il metodo push_back etc etc
Stiamo facendo un "flam" senza soluzione sulla questione "derivare or
wrappare" te ne stai rendendo conto spero.
|>| spero nessuno si insulti rispondendo "ma io non uso mai un pointer alla
|>| base"
|>altrimenti a che servirebbe.
|
|
| infatti č inutile e sbagliato derivare pubblicamente in C++ da un
| container della standard library , come volevo dimostrare, e come dimostra
| l'lsp
http://www.cuj.com/documents/s=8021/cuj0110lopiano/
Articolo scritto da un mio collega in cui deriva
da un std::vector e Meyer non ha avuto nulla da ridire.
|>Come uso poi NetList in una funzione con signature:
|>template <typename T>
|>void foo( const std::vector<T>& aVector) const;
|
|
| spiegami perché tale funzione( metodo a dire il vero vista la sign )
| non prende due iterator invece che una const reference ad un vector<T>
| ( come fanno tutti gli algorimiti in std:: boost:: & C ) ?
Perche esiste il suo gemello:
void foo( std::vector<T>& aVector);
e mi serve proprio che sia un vector:
aVector.push_back();
avrei dovuto forse scrivere:
void foo( std::vector<T>::const_iterator aBegin,
~          std::vector<T>::const_iterator aEnd) const;
come faccio forzare il fatto che entrambi gli iterator
appartengano alla stesso container ?
| anche questo č un caso di cattivo design.
Be opinione personale.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (MingW32)
Comment: Using GnuPG with Thunderbird - 
http://enigmail.mozdev.org
iD8DBQE/z8v67UpzwH2SGd4RAtYdAKCFvap9heRPZDmsNLEpIM+fvKFTegCfenhQ
8TwtUb0zEbsIboeorwehS7g=
=Ayi0
-----END PGP SIGNATURE-----

 Be opinione personale.
certamente personale , ma anche questo ampiamente
discusso in letteratura
-- 
Roberto Ferranti

 sto usando WeirdVector senza saperlo.
Ma non puoi scrivere 'delete vec;' senza rischiare disastri. Il tuo
disegno e' debole.
Ciao,
Nicola
P.S. Sospetto che tu lo sappia perfettamente, caro il mio "capatosta"
:-)

 articolo scritto da Sutter, il tuo collega ha qualcosa da ridire su questo?
e poi scusa, ma tu l'articolo del tuo collega l'hai letto?
<cite>
 [4] This inheritance could be problematic because std::vector's 
 destructor is not virtual and is not designed for inheritance, so the
 user should not use a NetVector<T> polymorphically as a std::vector<T>.
 In fact, this is unlikely to happen because the purpose of this class is
 to be a data member for other NetObject derived classes.
</cite>
sbirish.

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
sbirish wrote:
| On Fri, 05 Dec 2003 01:06:18 +0100, Gaetano Mendola wrote:
|
|
|>|>io posso scrivere  vec->push_back(3);
|>|>sto usando WeirdVector senza saperlo.
|
|
|>| puoi farlo anche wrappando.
|
|
|>E siamo daccordo ma devo ridefinire il metodo push_back etc etc
|>Stiamo facendo un "flam" senza soluzione sulla questione "derivare or
|>wrappare" te ne stai rendendo conto spero.
|
|
| spero tu ti stia rendendo conto che è la differenza tra codice che sta in
| piedi per caso e qualcosa di più solido, derivare pubblicamente da un
| container è come costruire un impianto elettrico coi fili scoperti e
| pretendere che sia a norma.
| "flame" btw, mi sembra, tuttavia, che sia una discussione civile;
| perlomeno finché la teniamo su questi toni.
Mi spieghi dove sta la pericolosita' o l'instabilita' di una classe
derivata da un container ? Conosci qualche metodo per far si che una
classe non sia derivabile ? Bene.
Perche' non e' stato fatto con i contenitori standard, forse perche'
non e' completamente sbagliato ?
|>| infatti è inutile e sbagliato derivare pubblicamente in C++ da un
|>| container della standard library , come volevo dimostrare, e come
|>| dimostra l'lsp
Ma non dimostra nulla, da soltanto una sua opinione.
|>
http://www.cuj.com/documents/s=8021/cuj0110lopiano/
|>Articolo scritto da un mio collega in cui deriva da un std::vector e
|>Meyer non ha avuto nulla da ridire.
|
|
| intendi Scott MeyerS come suppongo, o un più improbabile Bertrand Meyer?
Non capisco perche' devi fare il puntiglioso su una S scordata.
| 
http://www.gotw.ca/publications/mill18.htm
|
| articolo scritto da Sutter, il tuo collega ha qualcosa da ridire su
questo?
Andrebbe chiesto a Scott Meyers.
Cito da quell'articolo:
<< Should base class destructors be virtual?
[...]
The usual answer to this question is: "Huh? Of course base class
destructors should always be virtual!" This answer is wrong, and the C++
standard library itself contains counterexamples refuting it, but it's
right often enough to give the illusion of correctness. >>
poi continua ma arriva alla conclusione che non si puo dire o sbagliato.
| cosa fa foo() e perché dovrebbe essere proprio un vector?
Suppone che tutti gli elementi che appartengono al vettore
stiano in locazioni di memoria contigue.
| no, _probabilmente_ avresti dovuto scrivere
|
| template<typename In>
| void foo( In beginIter, In endIter ) ...
Certo e poi passare due iterator di una lista.
|>come faccio forzare il fatto che entrambi gli iterator appartengano alla
|>stesso container ?
|
|
| lo enforza la standard library?
|
| template<typename _InputIter, typename _Function>
| _Function
| for_each(_InputIter __first, _InputIter __last, _Function __f)
|
| template<typename _InputIter, typename _Predicate>
| inline _InputIter
| find_if(_InputIter __first, _InputIter __last, _Predicate __pred)
|
|
| ti risulta che questi due sopra siano esempi di pessimo stile?
No, ma come purtroppo ben sai proprio per essere cosi' poco intuitivi
sono usati quasi da nessuno, io ogni volta che devo usarli devo prendere
in mano il libro di Josuttis.
|>| anche questo è un caso di cattivo design.
|>Be opinione personale.
|
|
| certamente personale , ma anche questo ampiamente
| discusso in letteratura
E' discusso, e a destra e a sinistra si trovano pareri discordanti.
Si discute anche sul fatto che la multipla ereditarieta' sia da usare
o no.
Gaetano
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (MingW32)
Comment: Using GnuPG with Thunderbird - 
http://enigmail.mozdev.org
iD8DBQE/0Kpd7UpzwH2SGd4RAhXVAKCnMklhdzuT9qp03E/QBWaAm5ALDgCgvFZv
54dDO0MlBXHScmENTqv+OP0=
=Jlhe
-----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
sbirish wrote:
| On Fri, 05 Dec 2003 02:40:28 +0000, sbirish wrote:
|
|
|
|>>| infatti è inutile e sbagliato derivare pubblicamente in C++ da un
|>>| container della standard library , come volevo dimostrare, e come
|>>| dimostra l'lsp
|>>
|>>
http://www.cuj.com/documents/s=8021/cuj0110lopiano/
|>>Articolo scritto da un mio collega in cui deriva da un std::vector e
|>>Meyer non ha avuto nulla da ridire.
|>
|>intendi Scott MeyerS come suppongo, o un più improbabile Bertrand Meyer?
|>
|>
http://www.gotw.ca/publications/mill18.htm
|>
|>articolo scritto da Sutter, il tuo collega ha qualcosa da ridire su
questo?
|
|
| e poi scusa, ma tu l'articolo del tuo collega l'hai letto?
Tu che dici ?
| <cite>
|  [4] This inheritance could be problematic because std::vector's
|  destructor is not virtual and is not designed for inheritance, so the
|  user should not use a NetVector<T> polymorphically as a std::vector<T>.
|  In fact, this is unlikely to happen because the purpose of this class is
|  to be a data member for other NetObject derived classes.
| </cite>
"could be" not "is"
Non sto dicendo che e' safe farlo ma sicuramente non e' una cosa
demoniaca da evitare a tutti i costi. Basta essere coscienti di
quello che si sta facendo. Non credi che se fosse completamente
sbagliato lo standard avrebbe tolto la possibilita' di ereditare
da una classe con distruttore non virtuale ? Forse l'hanno fatto
perche' avere un metodo virtuale non e' gratis ?
G.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (MingW32)
Comment: Using GnuPG with Thunderbird - 
http://enigmail.mozdev.org
iD8DBQE/0K4w7UpzwH2SGd4RAnGjAKDHW9D2qbvnPBHKF+tX9h0pJkxczwCg1GGS
VDWTPYuX58pnpkdwOI5yvzM=
=VdOo
-----END PGP SIGNATURE-----

...
| [...]
|
|>Se un oggetto e derivato da un altro in maniera publica
|>stanno in relazione IS-A e WeirdVector sta in relazione
|>IS-A con vector.
|>
|>io posso scrivere  vec->push_back(3);
|>sto usando WeirdVector senza saperlo.
|
|
| Ma non puoi scrivere 'delete vec;' senza rischiare disastri. Il tuo
| disegno e' debole.
Rischio disastri solo se non so cosa c'e' dentro WeirdVector o sbaglio ?
| Ciao,
| Nicola
|
| P.S. Sospetto che tu lo sappia perfettamente, caro il mio "capatosta"
| :-)
Nicola da quanto tempo.
Ma certo che lo so a cosa vado in contro, ma mi da fastidio il
principio:
"Se una classe non ha il distruttore virtuale non puo essere
derivata".
E so che da fastidio anche a te.
Ma un altro incontro a Parigi invece che a Milano quando si fa ?
G.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (MingW32)
Comment: Using GnuPG with Thunderbird - 
http://enigmail.mozdev.org
iD8DBQE/0K737UpzwH2SGd4RAj71AKCljvKVjeoGaI0hAhdOIkysOzpTygCggr3z
AUGI/EZDsZjAONYmQnVoleo=
=suL1
-----END PGP SIGNATURE-----

 discute anche sul fatto che la multipla ereditarieta' sia da usare o no.
che è un discorso affatto pertinente con quello che stiamo facendo ( e
lungi da me spaziare fino a questo ).
-- 
Roberto Ferranti

 scusa il tono, ma questo č un tuo personale problema;
for_each e find_if sono obbrobri dettati da limitazioni idiosincratiche 
del C++. Boost ha abbondanza di modi per superarle, segno che esistono, 
che costituiscono un problema e che chi di dovere lo sa gią
-- 
  < 
http://www.reactos.com/
 >  Open source clone of Windows NT. Current
      Don't stand, REACT!      version 0.1.5. C, C++ and ASM developers
                               and beta testers are welcome!