Boost logo

Boost :

From: Ion Gaztañaga (igaztanaga_at_[hidden])
Date: 2006-03-05 04:52:58


Hi,

>> But when iterating through directories I find that that returning a
>> temporary object that must allocate/copy/deallocate hurts my
>> performance
>> paranoia. Even with move semantics we have a an overhead:
>
> On the other hand, I would guess that the actual OS and hard drive /
> network level operations take a lot more time than copying a few
> strings.

Yes. It's a wrong example, since a path has nothing to do with
filesystem operations. A path (in the current implementation) is just a
concatenation of strings representing a file or directory.

Once path is formed there is no access to filesystem. For example,
path.leaf() function is implemented as:

return m_path.substr( leaf_pos( m_path, m_path.size() ) );

So path is a memory class. A "pseudo-container" of strings. Using
path::iterator you can traverse those strings forming the path. Since
you have to make conversions you can't return references like in normal
containers in some cases, but returning values forces always a temporary
string.

> std::cout << it->root_name() << "append some data";
>
> Who says you want to store the result? A temporary might be just fine.

But what if you want to store it?

>> Couldn't be better (although uglier) to take a reference to a string
>> that will be filled?
>>
>> void fill_root_name(string_type &root_name) const;
>
> Really ugly! :-)
> It also assumes that the caller has somewhere to store the result. And
> the intention to keep it.

Couldn't we have both functions? Returning a copy forces always an extra
allocation/deallocation and you can't avoid it. So maybe instead of
replacing that function we can add a function saying we want to store
that result in our string.

>> ////////////////////////////////////////////////////////////////////
>>
>> std::vector<std::path> paths;
>> //fill with paths
>>
>> std::path::string_type root_name;
>>
>> root_name.reserve(PATH_LENGTH);
>
> So now you are wasting space instead. :-)
>
>> This way we only allocate memory if we don't have enough place in
>> our
>> string. We can also reserve it beforehand to speed up code.
>
> How do we know that speed is gained (and important), while space is
> cheaper?

Don't reserve anything, if you don't want to do it:

std::path::string_type root_name;
std::path::iterator beg = paths.begin(), end = paths.end();

for(; beg != end; ++it){
     it->fill_root_name(root_name);
}

This will save (end-beg) string constructions and destructions. Is this
a speed improvement. Well, that depends on:

-> what ++it does (current boost path::iterator increment is expensive,
but it does not need to, this is implementation detail)
-> what it->does (currently returns the address of the internal string)
-> the depth of the path

But I think that filling a string instead of returning a temporary one
is always faster. And there is another reason for avoiding allocation
apart from speed: memory fragmentation.

But as Beman has pointed out, I should not worry on implementation
details, but on the interface. And the interface is forcing me to have
temporaries in my code (for example like stringstream.str() function).
How ofter will I call "root_name()", "leaf()" and others in my code?
That will depend on the application type. My application maybe uses them
once, but an antivirus scanning or a music jukebox constructing a song
database will surely use them a lot.

Regards,

Ion


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk