Howard Hinnant, one of the Apple libc++ maintainers, kindly analyzed the
compilation failure of Timer.cpp and had the
following comments...
--------------------------------------------------------------------------------------------------------------------------------------------
The problem is here:
class Dict {
public:
typedef std::map<const std::string, boost::any> DataType; // <-------
When the copy assignment operator of Dict does:
_data = other._data;
(where _data is a DataType), then libc++ tries to assign to a *const*
std::string, and triggers the error.
The fix is simple: Remove the const from the std::string in DataType:
typedef std::map<std::string, boost::any> DataType;
This is an understandable error when upgrading from a C++03-based std::lib to a
C++11-based std::lib. You've stumbled across one of the very
few places that the committee broke API between C++03 and C++11. And the API
is broken for a very good reason: A very significant
performance optimization opportunity for [multi]map.
Background:
The C++98/03 [multi]map/set containers did not require the contained element to
be assignable, even for the copy assignment operator of these
containers. Instead the implementation was supposed to do an erase, or clear
of the lhs, followed by an insert for every element in the rhs.
In C++11 23.2.4 [associative.reqmts]/p7 (and there's a similar paragraph for
the unordered containers) transfers the requirements on
value_type (the pair<const key_type, mapped_type>), directly to the key_type
and mapped_type, specifically calling out CopyAssignable as an
example.
This allows the map copy assignment operator to recycle nodes (assign the
key_type and mapped_type within the nodes) as part of the assignment
process, in addition to using erase/insert. In your example, if _data.size()
== other._data.size(), and if all strings in other._data are
short, the assignment could be done with *zero* trips to the heap (*very
fast*). In contrast, every erase, and every insert results in at
least one deallocation and allocation respectively.
I'm not positive but I believe libc++ may be the only std::lib which currently
implements this optimization, and so compiling against other
std::libs would not trigger this error.
You can blame me for this API breakage in C++11. I believed (and still
believe) the cost in breakage is worth the performance benefit. I see
const-qualified types in containers very rarely (strictly speaking I think they
are not even allowed, but I would have to double check that).
Also libc++ follows the C++11 rules even with -std=c++03. The philosophy of
libc++ is that there are already plenty of C++03 std::libs.
libc++ emulates a C++11 environment, even when -std=c++03. This is meant to
aid clients in transition from C++03 to C++11. For example
std::shared_ptr and std::unordered_map are available even in -std=c++03.
If for some reason taking the const out of the DataType typedef is not
desirable, you can easily emulate the C++03 behavior (but giving up the
performance optimization) by replacing:
Dict &operator=(const Dict &other) {
_data = other._data;
return *this;
};
with:
Dict &operator=(const Dict &other) {
if (this != &other) {
_data.clear();
_data.insert(other._data.begin(), other._data.end());
}
return *this;
};
And this:
Dict(const Dict &other) {
_data = other._data;
};
with:
Dict(const Dict &other)
: _data(other._data)
{};
This latter change should be made whether or not you take the const out of
DataType. It is inefficient to default construct a data member
just to assign it a new value. Better to construct it directly to the desired
value.
-------------------------------------------------------------------------------------------------------------------------------------------
So the trivial patch....
--- RDKit_2013_06_1/Code/RDGeneral/Dict.h.orig 2013-11-03 13:22:27.000000000
-0500
+++ RDKit_2013_06_1/Code/RDGeneral/Dict.h 2013-11-03 13:22:54.000000000
-0500
@@ -32,7 +32,7 @@
//!
class Dict {
public:
- typedef std::map<const std::string, boost::any> DataType;
+ typedef std::map<std::string, boost::any> DataType;
Dict(){
_data.clear();
};
...allows RDKit_2013_06_1 to completely compile under Xcode 5.0.1 and libc++ on
Mac OS X 10.9.
Jack
------------------------------------------------------------------------------
Android is increasing in popularity, but the open development platform that
developers love is also attractive to malware creators. Download this white
paper to learn more about secure code signing practices that can help keep
Android apps secure.
http://pubads.g.doubleclick.net/gampad/clk?id=65839951&iu=/4140/ostg.clktrk
_______________________________________________
Rdkit-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/rdkit-discuss