Re: Simple const-related question
Kira Yamato wrote:
On 2008-02-18 20:05:51 -0500, Jeff Schwab <jeff@schwabcenter.com> said:
Daniel T. wrote:
On Feb 18, 5:45 pm, nsdevelo...@yahoo.com wrote:
On Feb 18, 6:30 pm, nsdevelo...@yahoo.com wrote:
[...]
Get out of the Java habit of putting () after the class name when
calling new. I'm pretty sure that "new Object();"
Allocates a default-constructed Object.
and "new Object;" do
Allocates a potentially uninitialized object, if Object is a POD type.
http://www.research.att.com/~bs/bs_faq2.html#malloc
I don't usually use the parentheses, either, but I guess I probably
should. I also don't usually allocate objects directly with new.
different things.
Just curious. Instead of directly using new, what do you usually use to
allocate objects?
Either the stack (sorry, "auto" storage) or one of the standard
containers. If I have dynamically allocated objects, I generally have
to store pointers to them somewhere anyway, so I let standard containers
deal with managing their lifetimes. For example, if I'll need an
unknown quantity of Foos, I just create a std::list<Foo> and use its
elements. Inserting or deleting list elements does not invalidate
pointers to the other elements.
Allan Holub has an interesting (very opinionated) take on
object-oriented design, which he summarizes in his "Getters and Setters
are Evil" article, and which he describes in depth in the APress book
"Holub on Patterns." The idea is essentially that rather than pulling
data from various sources into a controller object, he tries to push
commands to objects that already have access to the data. The down-side
is that the code implementing a given application is spread all over
creation. The up-side for me has been that because I'm pushing rather
than pulling, object methods rarely need to return pointers to anything.
If an object A knows how to create a Foo, and object B has to do
something with the Foo, A can usually just creates the Foo on the stack,
and pass it to Foo. Suppose the main "controller" function needs an
object of type Foo, but only object a knows how to create a Foo. Rather
than requesting a Foo from object a, the controller function passes a
Receiver object to object a's Foo creation method. Object a creates the
Foo on the stack, then passes it to the receiver. The receiver does
whatever is necessary with the Foo before returning, and the Foo is
automatically destroyed as the stack unwinds back to the controller
function. It's very much like passing an operation to a standard
algorithm like std::for_each, or passing an output iterator to
std::transform.
Suppose main() wants to print a Foo, but only object a can make a Foo.
The "pull" approach might look like this:
/* Pulling a Foo. */
#include <iostream>
#include <vector>
struct Foo { };
std::ostream& operator<<(std::ostream& out, Foo const& foo) {
return out << "Foo at " << &foo << '\n';
}
struct A {
~A() {
/* Delete any items in foo_. */
// ...
}
Foo* create_foo() {
foo_.push_back(new Foo);
return foo_.back();
}
private:
std::vector<Foo*> foo_;
};
int main() {
A a;
/* Somebody has to keep track of each foo. */
Foo* foo = a.create_foo();
std::cout << *foo;
}
The "push" approach gets rid of the dynamic memory allocation entirely.
A new static type has to be introduced (the receiver), but you no
longer need a container to keep track of the dynamically allocated
objects. In effect, the run-time stack is the container.
/* Pushing a Foo. */
#include <iostream>
struct Foo { };
std::ostream& operator<<(std::ostream& out, Foo const& foo) {
return out << "Foo at " << &foo << '\n';
}
struct Printing_receiver {
Printing_receiver(std::ostream& out):
out_(&out) { }
template<typename T>
void operator()(T const& t) const {
*out_ << t;
}
private:
std::ostream* const out_;
};
struct A {
template<typename Foo_receiver>
void create_foo(Foo_receiver const& receiver) {
Foo foo;
receiver(foo);
}
};
int main() {
A a;
a.create_foo(Printing_receiver(std::cout));
}
As long as the creation functions are re-entrant, you can do this as
much as you want, or at least until you run out of stack space. :)