Good idea or gimmick: Go-style OO-programming in C++ ?

Ö

Öö Tiib

This seems to assume that pointers are used exclusively for handling
dynamically allocated memory.

I did not tell what is used. Used are awful idioms. Just download
random C++ source from net and see. I did suggest rules how RAII can
be taken into usage in C++ very simply.
That's most certainly not so. Remember that pointers are, effectively,
iterators, and there are situations where you can (and should) use
pointers as iterators (eg. when calling or even implementing an
iterator-based algorithm.)

Can you give example where I must use raw pointers instead of full
iterators? Feels like some sort of preliminary optimization. On cases
that I know of the real iterators perform as well as raw pointers
while being more type-safe, having less operators and better
debug-time checks. So ... I need example.
There are also other (although rarer) cases where you may want pointers
that are not used as iterators, pointing to some non-dynamically allocated
thing.

Why? Storing such feels error-prone. Passing as argument feels pointless:
If it is not nullptr use reference, if it is nullptr use overload without
that parameter. Interfacing with module written in C ... I mentioned.
'new' is perfectly ok if you are implementing a class that manages its
own resources (as long as you use 'new' only inside that class and
strictly follow the "rule of three".)

Why to use new if you have nothing to initialize with it?
There are no raw pointers. Your complaint was that there may be
iterators and pointers to non-dynamic data. I disagreed on those too
but ... Do you want to initialize iterator with new? Do you want to
initialize pointer that can point at non-dynamic data with new?
Except if you are implementing such a class.

Same reason. It is preliminary optimization at best and usually just
pointless. The smart pointers mop up with zero code typed. It is
'reset()' not 'delete' with those if you need to do it explicitly
ahead of time. Some more exotic resources may need to close(), stop()
and/or terminate() ... but there's nothing to 'delete'.
 
T

Tobias Müller

Öö Tiib said:
Can you give example where I must use raw pointers instead of full
iterators?

Any type T with a valid std::iterator_traits<T> is a perfectly fine
iterator. There are no 'full' or 'half' iterators, just iterators.

You usually have to use the iterator type that is defined by the container.
And if this is a typedef to a pointer, then you cannot change that. Since
typedefs are just aliases, they don't introduce any new typesafety.

Tobi
 
J

Jorgen Grahn

I think it can be summarized as: "Never write 'new' in a function that's
not the member function of a class that takes care of automatically
handling that allocation."

Also: "Prefer handling objects by value, unless there's a good reason not
to (eg. because they are too large and inefficient to copy around)."

I don't even remember when was the last time I wrote 'new' in anything
but a member function (of a class that takes care of the allocated thing.)

I don't remember last time I used 'new', period.

/Jorgen
 
Ö

Öö Tiib

Any type T with a valid std::iterator_traits<T> is a perfectly fine
iterator. There are no 'full' or 'half' iterators, just iterators.

We did not discuss C++ standard here. We did talk of the subset of C++ that
I briefly described, where raw arrays and raw pointers are all forbidden.
I asked for example. So give please *example* of existing C++ implementation that contains std::shared_ptr, std::unique_ptr etc. ... but still uses raw
pointers as iterators for some standard container?
 
Ö

Öö Tiib

It depends on what the type of output you're considering. Humans can
certainly sense 10ms audio jitter. A good drummer can keep a beat to
that accuracy too. We do sound localization with differences under a
millisecond.

Yes, that was what i meant. Human does not notice how 10 ms pass but remarkable
events (that human *will* notice) may take place during it. So unpredictable 10 ms
delays in an application that controls or orchestrates such events can result with
annoying or even fatal outcome depending on problem domain.
 
J

jeti789

Am Mittwoch, 27. Februar 2013 10:29:29 UTC+1 schrieb Juha Nieminen:
No, an interface defines no code. It has only definitions. And Smalltalk has no interfaces.
 
J

Jorgen Grahn

What about GUi frameworks , like Qt?

I distinctly remember never using a GUI framework :)

My point wasn't that noone should ever use 'new', or that I never use
it -- just that you can do a lot of useful coding without needing it.
Not very surprising. And not worth mentioning -- except newbies still
post example code here which is liberally sprinkled with useless new
and new[].

/Jorgen
 
Ö

Öö Tiib

Am Mittwoch, 27. Februar 2013 10:29:29 UTC+1 schrieb Juha Nieminen:

No, an interface defines no code. It has only definitions. And Smalltalk
has no interfaces.

That is exactly what is odd.

There are only declarations and javadoc comments describing the intent.
No slightest bit of code. No way to add checks that verify that the
caller followed contract (preconditions) and if implementer
fulfilled it (post-conditions). Interface is like tattoo on skin:
useless but often ugly.

That is a terrible situation! Yet all those Java proponents describe
such a *major* *weakness* as outright advantage. How? It sucks bad.
 
S

Stefan Ram

Öö Tiib said:
No slightest bit of code. No way to add checks that verify that the
caller followed contract (preconditions) and if implementer
fulfilled it (post-conditions).

If someone wants to add such code, there are multiple ways.
For example, to use an abstract class instead of an interface.

To complain that interfaces are not intended to contain such
code is like to complain that a cup of coffee does not
contain any food, so one cannot eat it if one is hungry.
When one wants to eat something, one is free to order this in
addition or instead of coffee in the first place.

(To validate value constraints, one can also add annotations
to a bean. See:

http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html

.) There even are tricks to add implementations to an interface
in Java, IIRC:

interface A
{ java.lang.Runnable r = new java.lang.Runnable()
{ public void run(){ java.lang.System.out.println( "A" ); }}; }

public class Main
{ public static void main( final java.lang.String args[] )
{ A.r.run(); }}
 
Ö

Öö Tiib

If someone wants to add such code, there are multiple ways.
For example, to use an abstract class instead of an interface.

One can not in Java: multiple inheritance is forbidden.
To complain that interfaces are not intended to contain such
code is like to complain that a cup of coffee does not
contain any food, so one cannot eat it if one is hungry.

But why interface may not contain checks that it is correctly used and implemented? I constantly use exactly such interfaces:

class Interface
{
public:
/// doc describing what interface does for outside world
RetType AMethod( Param param )
{
if ( param.isBad() )
throw std::invalid_argument( "Interface::AMethod passed"
" argument 'param' should not be bad.");
if ( !isPreparedForAMethod() )
return RetType();
RetType ret( doAMethod( param ) );
if ( ret.isTrash() )
throw std::logic_error( "Interface::AMethod the implementation"
" returned trash that it should not.");
return ret;
};
private:
/// doc describing what implementer should implement here
virtual bool isPreparedForAMethod() const = 0;
virtual RetType doAMethod( Param param ) = 0;
};

Ok, you say it is *not* interface but why should I care? For me it is exactly
the *correct* way to implement an interface. It keeps concerns of interface
semantics and its implementation separated.
When one wants to eat something, one is free to order this in
addition or instead of coffee in the first place.

You can't in Java, that was my point.
(To validate value constraints, one can also add annotations
to a bean. See:

http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html

See yourself, there are no way how I call isBad() on argument or isTrash() on
return value.
.) There even are tricks to add implementations to an interface
in Java, IIRC:

Sure, there are hacks how to get somehow around the major shortcoming.
That is why I am surprised. They are so proud about that single inheritance
and code-less interfaces and then hack there and do tricks and are still
so proud about that.
 
S

Stefan Ram

Öö Tiib said:
One can not in Java: multiple inheritance is forbidden.

One can use multiple inheritance of interfaces + delegation
of implementations (often delegation is preferable to
inheritance anyway).
But why interface may not contain checks that it is correctly
used and implemented? I constantly use exactly such interfaces:

Because in Java such »interfaces« are called »abstract classes«.
With abstract classes you can do this. It is called »template
method pattern«. (With interfaces one uses the »strategy pattern«
instead, which actually often is preferable.)
 
Ö

Öö Tiib

One can use multiple inheritance of interfaces + delegation
of implementations (often delegation is preferable to
inheritance anyway).

That is true, however that is concern of implementer. Interface's are usually written by architects. Architect wants to have it verified that the
interface is correctly implemented and used, and he often does not have
time to review all the code written.
Because in Java such »interfaces« are called »abstract classes«..
With abstract classes you can do this. It is called »template
method pattern«. (With interfaces one uses the »strategy pattern«
instead, which actually often is preferable.)

Again, the patterns used behind scenes are concerns of concrete designers.
Module should outside look and behave like architect said and the interfaces
can not be plain "tattoos" otherwise all hell gets loose and wrong teams get
blamed for misdoings of others.
 
J

jeti789

But why interface may not contain checks that it is correctly used and implemented? I constantly use exactly such interfaces:



class Interface

{

public:

/// doc describing what interface does for outside world

RetType AMethod( Param param )

{

if ( param.isBad() )

throw std::invalid_argument( "Interface::AMethod passed"

" argument 'param' should not be bad..");

if ( !isPreparedForAMethod() )

return RetType();

RetType ret( doAMethod( param ) );

if ( ret.isTrash() )

throw std::logic_error( "Interface::AMethod the implementation"

" returned trash that it should not.");

return ret;

};

private:

/// doc describing what implementer should implement here

virtual bool isPreparedForAMethod() const = 0;

virtual RetType doAMethod( Param param ) = 0;

};



Ok, you say it is *not* interface but why should I care? For me it is exactly

the *correct* way to implement an interface. It keeps concerns of interface

semantics and its implementation separated.

This looks to me at first sight like you were using multiple inheritance todo programming with traits, see http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-5

Nothing bad about it. But you can't do that in Java since Java interfaces contain definitions only. In JDK8 methods in interfaces may define a body: http://www.javabeat.net/2012/05/virtual-extension-methods-in-java-8/ But they may still not define inst vars as traits in Scala (aka stateful traits) or when using MI as in C++.

-- Oliver
 
A

Alain Ketterlin

One can use multiple inheritance of interfaces + delegation
of implementations (often delegation is preferable to
inheritance anyway).


Because in Java such »interfaces« are called »abstract classes«.
With abstract classes you can do this. It is called »template
method pattern«. (With interfaces one uses the »strategy pattern«
instead, which actually often is preferable.)

Not completely, because you can only have a single abstract base
class in Java, whereas in C++ you can as many as you wish.

.... unless you end up with a diamond-shaped inheritance graph, where
everything more or less breaks (virtual inheritance is of almost no help
since it requires changing the intermediate classes, and has an impact
on all sub-classes, e.g., for constructors). So, C++ support for MI is
also restricted, compared to other languages like CLOS or... Python (and
probably others) which have implicit disambiguation rules.

The problem with Java is that it has a root class, therefore any form of
multiple inheritance leads to a diamond, which is not the case with C++.
Interfaces have been invented to "break" the diamond. (BTW, I see no
real reason why interfaces should not be allowed to contain methods like
the one shown by Öö; the restrictions are fairly easy to check by the
compiler -- someone elsethread mentioned a progress on this point for
Java8.)

-- Alain.
 
Ö

Öö Tiib

This looks to me at first sight like you were using multiple inheritance to
do programming with traits, see http://www.codecommit.com/blog/scala/scala-
for-java-refugees-part-5

Not sure, it is in C++ called:
"Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals"
Rest call it sometimes as "template method design pattern".
Nothing bad about it. But you can't do that in Java since Java interfaces
contain definitions only.

That I know.
 
S

Seungbeom Kim

I think it can be summarized as: "Never write 'new' in a function that's
not the member function of a class that takes care of automatically
handling that allocation."

That's too narrow. I consider it okay to pass the 'new' expression
directly to a member function of a class that takes care of automatically
handling that allocation, e.g.:

std::unique_ptr<X> px(new X(...));

px.reset(new X(...));
 
W

woodbrian77

I can summarize it like that for C++:



* As pointers use only smart pointers Prefer std::unique_ptr and

std::shared_ptr (with its weak brother). std::auto_ptr has odd

semantics but is otherwise fine too.



* You may pass references to smart pointers, but you may not store

those.



* Never dereference a pointer without comparing it with 'nullptr'

first. Always check the results of std::weak_ptr::lock().



* Never take out raw pointer from smart pointer unless interfacing

with module written in C.



* Use keyword 'new' only in context of initializing or assigning

to std::unique_ptr or even better write 'make_unique' template

(it is just missing from standard ATM) and do not ever use

'new' in C++ code.



* Never use keyword 'delete'.

I will report one thing.

#if 0
char* CstringGive ()
{
::cmw::marshalling_integer slen(*this);
char* cstr = ::new char[slen.value + 1];

try {
Give(cstr, slen.value);
*(cstr + slen.value) = '\0';
} catch (...) {
::delete [] cstr;
throw;
}
return cstr;
}
#else
char* CstringGive ()
{
::cmw::marshalling_integer slen(*this);
::std::unique_ptr<char[]> cstr:):new char[slen.value + 1]);

Give(cstr.get(), slen.value);
*(cstr.get() + slen.value) = '\0';
return cstr.get();
}
#endif

An executable produced by g++ 4.7.2 with -Os is 32 bytes
larger using the second version than the first. Maybe it's
a weakness of this compiler? :)


Brian
Ebenezer Enterprises - impeach Obama.
http://webEbenezer.net
 
Ö

Öö Tiib

I will report one thing.

#if 0
char* CstringGive ()
{
::cmw::marshalling_integer slen(*this);
char* cstr = ::new char[slen.value + 1];
try {
Give(cstr, slen.value);
*(cstr + slen.value) = '\0';
} catch (...) {
::delete [] cstr;
throw;
}
return cstr;
}

#else

char* CstringGive ()

Error! I see 'char*' my rules suggested against raw pointers. ;)
{

::cmw::marshalling_integer slen(*this);

::std::unique_ptr<char[]> cstr:):new char[slen.value + 1]);

You should not use smart pointers for dynamic arrays. Use std::vector
or std::string. Smart pointer does 'delete', not 'delete[]' and so
you result with undefined behavior.
Give(cstr.get(), slen.value);
*(cstr.get() + slen.value) = '\0';
return cstr.get();
}
#endif

An executable produced by g++ 4.7.2 with -Os is 32 bytes
larger using the second version than the first. Maybe it's
a weakness of this compiler? :)

Some bytes here or there. I was suggesting that RAII is better
versus GC. Stefan Ram asked how to avoid leaks, I suggested
robust rules for applying RAII. I did not say that it is
cost-free in all situations. 'char*' usually loses even to
'std::string' in performance. Vital length information is
missing in 'char*'. That is important for most operations
with strings and so algorithms have to search for terminator
'\0' with it.
 
W

woodbrian77

char* CstringGive ()



Error! I see 'char*' my rules suggested against raw pointers. ;)


{
::cmw::marshalling_integer slen(*this);
::std::unique_ptr<char[]> cstr:):new char[slen.value + 1]);



You should not use smart pointers for dynamic arrays. Use std::vector

or std::string. Smart pointer does 'delete', not 'delete[]' and so

you result with undefined behavior.

This page --
http://en.cppreference.com/w/cpp/memory/unique_ptr
-- says,

"There are two versions of std::unique_ptr:

1) Manages the lifetime of a single object (e.g. allocated with new)

2) Manages the lifetime of a dynamically-allocated array of objects (e.g. allocated with new[])"
Some bytes here or there. I was suggesting that RAII is better

versus GC. Stefan Ram asked how to avoid leaks, I suggested

robust rules for applying RAII. I did not say that it is

cost-free in all situations.


You also said,
"Never dereference a pointer without comparing it with
'nullptr' first."

Do you object to this line:
::cmw::marshalling_integer slen(*this);
?


Brian
Ebenezer Enterprises - John 3:16.
http://webEbenezer.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top