Class#Allocate and Its Uses

Class#allocate and its uses

The main reason allocate exists is to allow you to build custom constructors for your objects. As the article you linked mentioned, you can envision the SomeClass.new method as doing something like the following by default:

class SomeClass
def self.new(*a, &b)
obj = allocate

# initialize is a private instance method by default!
obj.send(:initialize, *a, &b)
end
end

Despite what the documentation says, the existence of the allocate method is not so much about memory management as it is about providing some finer grained control over the object creation lifecycle. Most of the time, you won't need this feature, but it is useful for certain edge cases.

For example, in the Newman mail framework, I used this technique to implement a fake constructor for a TestMailer object; it implemented the new method for API compatibility, but actually returned a single instance regardless of how many times it was called:

class Newman::TestMailer
def self.new(settings)
return self.instance if instance

# do some Mail gem configuration stuff here

self.instance = allocate
end

attr_accessor :instance
end

I've not seen many other use cases apart from redefining new as shown above (although I imagine that some weird serialization stuff also uses this feature). But with that in mind, it's worth pointing out that Ruby consistently provides these kinds of extension points, regardless of whether or not you'll need to use them regularly. Robert Klemme has a great article called The Complete Class which I strongly recommend reading if you want to see just how far this design concept has been taken in Ruby :-)

Why is Class#allocate a public method in Ruby?

Deserialization comes to mind. A class may be serializable but might not have an initialize that takes no arguments, and that code shouldn't need to initialize it to something just to immediately undo that work.

Basically any scenario where you initialize an object differently then your typical case it becomes useful to separate those two steps.

Why does the Quantlib::Error class allocate a std::string on the heap?

This is following the behavior of standard library exception types.

They are supposed to be copyable without throwing exceptions, since throwing an exception during construction of an exception handler parameter would cause a call to std::terminate (and possibly in some other situations requiring a copy of the exception as well).

If std::string was used directly, copying the exception could cause for example a std::bad_alloc to be thrown. Using a reference-counted pointer instead avoids that.

The difference between initialize and self.new

allocate allocates the memory for an instance of Foo but does not initialize it.

initialize is called on an already allocated object to initialize (set the initial values of) an instance of Foo.

The default implementation of new calls both of these:

class Foo
def self.new(*args, &blk)
obj = allocate
obj.initialize(*args, &blk)
obj
end
end

Note: The default implementation of new is usually written natively (e.g. in C, for MRI), not in Ruby. The snippet above is the Ruby that has the same effect as the native implementation.

So you see, the two are not quite the same, although they are both used in the construction of a new instance of Foo.

If your initialize method was empty to begin with, and it took no arguments, then yes, you could just replace your definition of Foo.new with what is essentially an alias of Foo.allocate, but in all other cases, only by calling Foo.new can you get a properly initialized version of your object.

(I would recommend to sticking with just calling new on your classes, even if they don't require initialization, because it abstracts away the allocation of memory).

Does returning a std::string from a class allocate memory?

For the std::string:

#include <string>
class Bla
{
public:
Bla() {}

const std::string& GetStr() const
{
return m_Str;
}

private:
std::string m_Str = "Hi";
};

int main() {
Bla bla;
std::string currentString = bla.GetStr(); //1. will allocate new string
const std::string& secondString = bla.GetStr(); //2. will be a const reference to m_Str
if (bla.GetStr() == "abc") {} //3. will be a const reference to m_str, and therefore not another allocated string
}

If you assign the result of GetStr(), which is a const reference, to a normal std::string, like 1., the string will be allocated.

If you assign the result of GetStr(), which is a const reference, to another const reference, like 2., they will be referencing the same object, which is m_Str.

If you compare the result of GetStr(), which is a const reference, to another string or to a string literal, like 3., a string will not be allocated, and the comparison will take place with the referenced object, in this case m_Str with the other string, in this case a const char[] (aka string literal). (The one being compared to here is "abc").

m_Str will be allocated, however.

For the std::vector:

If the result of the function returning the std::vector& is assigned to a normal std::vector (not a reference), it is allocated.

If the result of the function returning the std::vector& is assigned to another reference to a vector, then it will not be allocated.

If the result of the function returning the std::vector& is compared to another std::vector or std::vector& using a comparison operator, it is not allocated.

Edit: As Evg pointed out, the operator == has an overload that takes a std::string and a const char*. If it did not exist, bla.GetStr() == "abc" would have had to construct and allocate a new string from "abc" to be able to compare the two.

Does an instantiation of a derived class allocate memory for private members of base class?

Yes. A class object contains all of its direct non-static data members, and those of any base-class sub-objects. Access specifiers make no difference; they merely restrict where names can be used.

Does derived class allocate memory for member variable?

When you create an object of the derived class, a base class sub-object is embedded in the memory layout of the derived class object. So, to your question, there's only on variable that will be a part of the derived object.
Since, we are only taking about non-static members here, each derived object gets its base-class sub-object laid out in memory.
When you create a base class object, its a different piece of memory representing different object and has nothing to do with derived object created earlier.

Hope it clarifies your doubt!

This is a great book to understand C++ object model:

http://www.amazon.com/Inside-Object-Model-Stanley-Lippman/dp/0201834545/ref=sr_1_1?ie=UTF8&qid=1412535828&sr=8-1&keywords=inside+c%2B%2B+object+model



Related Topics



Leave a reply



Submit