[core/noncopyable][test/boost::unit_test::singleton] massive test failures
Hi, There's a problem with noncopyable and boost::unit_test::singleton in Intel 13 for Linux in C++11 compatibility mode that's rippling through many Boost libs. To list a few: date_time: http://tinyurl.com/lkeakab geometry: http://tinyurl.com/n3rajyn regex: http://tinyurl.com/kxkqo4c tuple: http://tinyurl.com/oz3vlct The error messages go like protected function "boost::noncopyable_::noncopyable::noncopyable()" [...] is not accessible through a "boost::noncopyable_::noncopyable" pointer or object[...] protected function "boost::unit_test::singleton<Derived>::singleton()" [...] is not accessible through a "boost::unit_test::singletonboost::unit_test::unit_test_log_t" pointer or object[...] which are manifestations of the following compiler bug: https://software.intel.com/en-us/forums/topic/404755 The report also indicates a simple workaround consisting of replacing BOOST_CONSTEXPR noncopyable() = default; with noncopyable() {} (seemingly, this would also fix boost::unit_test::singleton automatically.) Maybe the maintainer of boost:noncopyable can try a fix for ICC 13 along these lines? This can potentially clear a ton of yellow cells. I'd volunteer a pull request but alas I don't have local access to that compiler. Thank you, Joaquín M López Muñoz Telefónica
Joaquin M Lopez Munoz wrote:
There's a problem with noncopyable and boost::unit_test::singleton in Intel 13 for Linux in C++11 compatibility mode that's rippling through many Boost libs. [...]
Not that this has anything to do with the specific issue, but I wonder why noncopyable has been changed to use the shiny new =delete/constexpr/=default features - there wasn't anything wrong with the old implementation. I also wonder if people realize that noncopyable is now, by my reading of the standard, a trivial class. This includes trivially copyable.
2014-08-21 13:38 GMT+04:00 Joaquin M Lopez Munoz
Hi,
There's a problem with noncopyable and boost::unit_test::singleton in Intel 13 for Linux in C++11 compatibility mode that's rippling through many Boost libs. To list a few:
This is already being solved: https://github.com/boostorg/config/pull/34 -- Best regards, Antony Polukhin
Antony Polukhin
2014-08-21 13:38 GMT+04:00 Joaquin M Lopez Munoz
: Hi,
There's a problem with noncopyable and boost::unit_test::singleton in Intel 13 for Linux in C++11 compatibility mode that's rippling through many Boost libs. To list a few:
This is already being solved: https://github.com/boostorg/config/pull/34
OK! Good to know, thank you, Joaquín M López Muñoz Telefónica
There's a problem with noncopyable and boost::unit_test::singleton in Intel 13 for Linux in C++11 compatibility mode that's rippling through many Boost libs. To list a few:
This is already being solved: https://github.com/boostorg/config/pull/34
Sort of... this fix depends on setting an undocumented and untested config macro that was added while I wasn't paying attention. It raises a whole host of questions frankly: 1) Why on earth is: BOOST_CONSTEXPR noncopyable() = default; Better than noncopyable() {} The latter with or without a BOOST_CONSTEXPR? 2) Are any of the new features of noncopyable tested - if there are testable new features that is? 3) Should the undocumented/tested macro BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS exist at all, or should we disable the feature altogether (ie set BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) for these problem cases/compilers? Finally, I note that comments on Github are all very well, but many interested parties may miss the discussion altogether - we're all guilty of this I realise - but it's important not to forget the mailing list - so many thanks to Joaquin for raising this to wider awareness! Cheers, John.
On Thursday 21 August 2014 13:07:03 John Maddock wrote:
There's a problem with noncopyable and boost::unit_test::singleton in Intel 13 for Linux in C++11 compatibility mode that's rippling through many
Boost libs. To list a few: This is already being solved: https://github.com/boostorg/config/pull/34
Sort of... this fix depends on setting an undocumented and untested config macro that was added while I wasn't paying attention.
That was my omission, sorry about that. I'm working on it now and today will file a pull request addressing your comments to the commit.
It raises a whole host of questions frankly:
1) Why on earth is:
BOOST_CONSTEXPR noncopyable() = default;
Better than
noncopyable() {}
The latter with or without a BOOST_CONSTEXPR?
In the particular case with noncopyable, its constructor should be as little imposing as possible because the derived class inherits its restrictions. In the second case the derived class will have non-trivial and non-constexpr default constructor.
2) Are any of the new features of noncopyable tested - if there are testable new features that is?
The test for noncopyable doesn't verify that the constructor is constexpr, if that's what you mean.
3) Should the undocumented/tested macro BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS exist at all, or should we disable the feature altogether (ie set BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) for these problem cases/compilers?
Well, the compiler does support public defaulted functions, so the feature is not totally broken. This is often enough in real world so it's not useless. I'd prefer to keep the two macros separated (that's why I added a new macro instead of using BOOST_NO_CXX11_DEFAULTED_FUNCTIONS).
John Maddock wrote:
1) Why on earth is:
BOOST_CONSTEXPR noncopyable() = default;
Better than
noncopyable() {}
I can tell you what's the difference, but not why it's better. :-) constexpr on the constructor enables noncopyable, and its descendants, to be statically initialized. I suppose this makes sense; a mutex, for example, is noncopyable but it may be desirable for it to support static initialization. =default makes the constructor trivial. A trivial constructor can be omitted. It's not clear to me why a noncopyable class would need to have a trivial constructor. Similarly, =default on the destructor instead of {} makes it trivial. A trivial destructor may be omitted. It makes approximately zero sense for a noncopyable class to have a trivial destructor. The funniest part is that =delete on the copy constructor makes the copy constructor trivial as well, in C++11. A trivial copy constructor means that the class is copyable with memcpy. :-) (There is a core defect report against that though, if I'm not mistaken.) In summary, I don't see the new noncopyable as better than the old one in any significant way.
On Thursday 21 August 2014 16:08:40 Peter Dimov wrote:
John Maddock wrote:
1) Why on earth is:
BOOST_CONSTEXPR noncopyable() = default;
Better than
noncopyable() {}
I can tell you what's the difference, but not why it's better. :-)
=default makes the constructor trivial. A trivial constructor can be omitted. It's not clear to me why a noncopyable class would need to have a trivial constructor.
Similarly, =default on the destructor instead of {} makes it trivial. A trivial destructor may be omitted. It makes approximately zero sense for a noncopyable class to have a trivial destructor.
Why do you think it's not sensible to have a trivial default constructor/destructor for a non-copyable class? I don't think noncopyable should guess on user's class semantics. It should do exactly what it is required to and nothing more, and defaulted functions achieve that.
The funniest part is that =delete on the copy constructor makes the copy constructor trivial as well, in C++11. A trivial copy constructor means that the class is copyable with memcpy. :-)
Technically, you can apply memcpy to any object and deal with the consequences. I don't see why noncopyable should attempt to do anything about it (and having non-trivial constructor actually doesn't do anything about it).
Andrey Semashev wrote:
Why do you think it's not sensible to have a trivial default constructor/destructor for a non-copyable class?
Because it isn't. Think about it. Trivial constructors and destructors do nothing at all. A trivial constructor leaves the object uninitialized. But it's possible I'm constrained by my lack of imagination; show me one example.
Technically, you can apply memcpy to any object and deal with the consequences.
Technically... if an object has a trivial copy constructor it's well defined to use memcpy to copy it. See 3.9/3.
On Thursday 21 August 2014 16:26:06 Peter Dimov wrote:
Andrey Semashev wrote:
Why do you think it's not sensible to have a trivial default constructor/destructor for a non-copyable class?
Because it isn't. Think about it. Trivial constructors and destructors do nothing at all. A trivial constructor leaves the object uninitialized.
But it's possible I'm constrained by my lack of imagination; show me one example.
For example, an object that is supposed to be initialized by a method call. The initialization is not done in the constructor because the object is supposed to be declared in the namespace scope and not pose thread safety issues. A global mutex, for instance. Another example, a global placeholder used as an anchor for DSL expressions or something like that. Think of something similar to std::cout.
Technically, you can apply memcpy to any object and deal with the consequences.
Technically... if an object has a trivial copy constructor it's well defined to use memcpy to copy it. See 3.9/3.
Right, I'm not arguing with that.
Andrey Semashev wrote:
For example, an object that is supposed to be initialized by a method call. The initialization is not done in the constructor because the object is supposed to be declared in the namespace scope and not pose thread safety issues. A global mutex, for instance.
And, I suppose, there is a corresponding method call to destroy it? While I can grant you this example, it doesn't seem particularly convincing. There are so many things you should remember not to do with the class, accidental copies are not a primary concern.
Another example, a global placeholder used as an anchor for DSL expressions or something like that. Think of something similar to std::cout.
There's no reason to make that noncopyable, unless of course we contort the example further and posit that we have several such placeholders of the same type that are to be distinguished by address. There do exist real-world examples of such 'tokens' - you can give the address of the object to a kernel synchronization primitive, say - but again, you have to be very careful to only have static variables of that class. Anyway, let's suppose that those things do exist. What percentage of noncopyable uses will be of this kind? More than 0.1%? It's not like you can't make your class noncopyable of just the right type without using the base class. Stated differently, were the changes driven by any kind of user demand?
On Thursday 21 August 2014 18:03:02 Peter Dimov wrote:
Andrey Semashev wrote:
For example, an object that is supposed to be initialized by a method call. The initialization is not done in the constructor because the object is supposed to be declared in the namespace scope and not pose thread safety issues. A global mutex, for instance.
And, I suppose, there is a corresponding method call to destroy it?
One may rely on the system reclaiming the resources at program termination. I know, it sounds ugly, but sometimes you have to do ugly things. Anyway, it's not really relevant.
While I can grant you this example, it doesn't seem particularly convincing. There are so many things you should remember not to do with the class, accidental copies are not a primary concern.
Another example, a global placeholder used as an anchor for DSL expressions or something like that. Think of something similar to std::cout.
There's no reason to make that noncopyable, unless of course we contort the example further and posit that we have several such placeholders of the same type that are to be distinguished by address. There do exist real-world examples of such 'tokens' - you can give the address of the object to a kernel synchronization primitive, say - but again, you have to be very careful to only have static variables of that class.
The object could perform lazy initialization on its first use. For instance, if it's a global logger it could open a file descriptor on the first record and prohibit copying to be able to finalize the file correctly (e.g. write a footer, perform rotation, whatever). Anyway, let's not argue about theoretical examples. I believe there are different circumstances in the real world and in some cases such design may be reasonable. I'm also sure that the real life is able to surprise me in unexpected ways, so I try to avoid assumptions. My point was that noncopyable should not impose any constraints on the user's class beyond the ones needed. The fact that it did before C++11 is not an advantage but the necessary evil people had to put up with. I don't see why we should keep it when we no longer have to.
Anyway, let's suppose that those things do exist. What percentage of noncopyable uses will be of this kind? More than 0.1%? It's not like you can't make your class noncopyable of just the right type without using the base class.
Sure, but following that logic noncopyable shouldn't have existed in the first place. It's not that difficult to declare a few functions private/deleted, after all. But still it exists and as such it has to do its job well.
Stated differently, were the changes driven by any kind of user demand?
Well, there was this ticket: https://svn.boost.org/trac/boost/ticket/6578 I don't remember any discussions on the ML though.
Andrey Semashev wrote:
My point was that noncopyable should not impose any constraints on the user's class beyond the ones needed. The fact that it did before C++11 is not an advantage but the necessary evil people had to put up with.
What is your justification for this claim?
Sure, but following that logic noncopyable shouldn't have existed in the first place.
No, this does not follow (even though I agree that it shouldn't have existed :-). The fact that noncopyable only works for 99.4% of the uses does not imply that it should not be provided.
Stated differently, were the changes driven by any kind of user demand?
Well, there was this ticket:
Yes, I know. You'll note that it cites no reasons for the change and provides no examples of noncopyable's supposed inadequacy. It's just "C++11 is shiny, let's make use of it!"
On Thursday 21 August 2014 19:08:54 Peter Dimov wrote:
Andrey Semashev wrote:
My point was that noncopyable should not impose any constraints on the user's class beyond the ones needed. The fact that it did before C++11 is not an advantage but the necessary evil people had to put up with.
What is your justification for this claim?
That's common sense, IMO. The side effects of noncopyable may be non-critical in most cases but not all. C++11 removes these side effects making noncopyable closer to what it actually should be.
Sure, but following that logic noncopyable shouldn't have existed in the first place.
No, this does not follow (even though I agree that it shouldn't have existed :-). The fact that noncopyable only works for 99.4% of the uses does not
imply that it should not be provided.
...but we shouldn't make that 99.9%? I don't think I understand your point.
Stated differently, were the changes driven by any kind of user demand?
Well, there was this ticket:
Yes, I know. You'll note that it cites no reasons for the change and provides no examples of noncopyable's supposed inadequacy. It's just "C++11 is shiny, let's make use of it!"
There are benefits from C++11 in noncopyable, it's not a change for nothing.
Andrey Semashev wrote:
On Thursday 21 August 2014 19:08:54 Peter Dimov wrote:
Andrey Semashev wrote:
My point was that noncopyable should not impose any constraints on the user's class beyond the ones needed. The fact that it did before C++11 is not an advantage but the necessary evil people had to put up with.
What is your justification for this claim?
That's common sense, IMO.
It's not, sorry. "People have had to put up with noncopyable's shortcomings" is a factual claim, it requires that there were at least two persons (hence the plural) that have had specific problems.
There are benefits from C++11 in noncopyable, it's not a change for nothing.
Out of curiosity... do you use noncopyable?
On Thursday 21 August 2014 19:34:27 Peter Dimov wrote:
Out of curiosity... do you use noncopyable?
I used to long time ago. By the way, one of the use cases where noncopyable failed for me was a wrapper around pthread_mutex_t offering a C++ interface for the mutex but still allowing the aggregate initialization. There were probably other cases, I just remembered this one for some reason.
Andrey Semashev wrote:
By the way, one of the use cases where noncopyable failed for me was a wrapper around pthread_mutex_t offering a C++ interface for the mutex but still allowing the aggregate initialization. There were probably other cases, I just remembered this one for some reason.
This is a good example; I tried that with the new implementation out of curiosity, and it doesn't seem to work. It would have helped the cause had it worked. :-)
On 8/21/2014 9:08 AM, Peter Dimov wrote:
Andrey Semashev wrote:
Stated differently, were the changes driven by any kind of user demand?
Well, there was this ticket:
Yes, I know. You'll note that it cites no reasons for the change and provides no examples of noncopyable's supposed inadequacy. It's just "C++11 is shiny, let's make use of it!"
Dammit, this thread makes me mad. A totally pointless change that broke a bunch of stuff. When will people learn? </rant>
On 21/08/2014 10:08 a.m., Peter Dimov wrote:
John Maddock wrote:
1) Why on earth is:
BOOST_CONSTEXPR noncopyable() = default;
Better than
noncopyable() {}
I can tell you what's the difference, but not why it's better. :-)
constexpr on the constructor enables noncopyable, and its descendants, to be statically initialized. I suppose this makes sense; a mutex, for example, is noncopyable but it may be desirable for it to support static initialization.
=default makes the constructor trivial. A trivial constructor can be omitted. It's not clear to me why a noncopyable class would need to have a trivial constructor.
The class inheriting from `noncopyable` is the one that should decide whether the constructor should be trivial or not. Defaulting the default constructor makes this decision possible.
Similarly, =default on the destructor instead of {} makes it trivial. A trivial destructor may be omitted. It makes approximately zero sense for a noncopyable class to have a trivial destructor.
Having a defaulted destructor is redundant, but explicit. I don't see why `noncopyable` ever needed to spell out a destructor. But the same point as above applies, specially since a literal class requires a trivial destructor, so a constexpr default constructor only makes sense with a trivial destructor (IIRC it's an error otherwise).
The funniest part is that =delete on the copy constructor makes the copy constructor trivial as well, in C++11. A trivial copy constructor means that the class is copyable with memcpy. :-)
This is not so funny once you accept that `TriviallyCopyable` does not imply `Copyable`. The apparent contradiction that `noncopyable` is `TriviallyCopyable` is not such, according to the language rules.
(There is a core defect report against that though, if I'm not mistaken.)
There is, but core wants to keep deleted special members trivial. I believe this to be the correct approach, and I don't think it's likely to change if anything else because it would be a breaking ABI change. This is off-topic anyway.
In summary, I don't see the new noncopyable as better than the old one in any significant way.
I disagree. The new implementation does not interfere with things other than copyability. Regards, -- Agustín K-ballo Bergé.- http://talesofcpp.fusionfenix.com
Agustín K-ballo Bergé wrote:
This is not so funny once you accept that `TriviallyCopyable` does not imply `Copyable`. The apparent contradiction that `noncopyable` is `TriviallyCopyable` is not such, according to the language rules.
The fact that a class can be trivially copyable but not copyable is precisely what's funny. If you don't 'accept' that, there's nothing left to laugh at. And, while I can grudgingly accept the argument that the class deriving from noncopyable needs to decide whether to be trivially constructible or not, in this case, it is not that class that makes the decision. All classes deriving from noncopyable weren't trivially copyable with the old implementation and are now trivially copyable.
This is off-topic anyway.
It isn't. We're discussing whether noncopyable is or should be trivially copyable, and the decision on that defect report determines whether the current implementation is. Incidentally, the compilers I tried give 0 for is_trivial and is_trivially_copyable. They don't seem enlightened.
I disagree. The new implementation does not interfere with things other than copyability.
"Does not interfere" is not the same as "is better than".
On 21/08/2014 11:54 a.m., Peter Dimov wrote:
Agustín K-ballo Bergé wrote:
This is not so funny once you accept that `TriviallyCopyable` does not imply `Copyable`. The apparent contradiction that `noncopyable` is `TriviallyCopyable` is not such, according to the language rules.
The fact that a class can be trivially copyable but not copyable is precisely what's funny. If you don't 'accept' that, there's nothing left to laugh at.
I guess we are saying the same thing.
And, while I can grudgingly accept the argument that the class deriving from noncopyable needs to decide whether to be trivially constructible or not, in this case, it is not that class that makes the decision. All classes deriving from noncopyable weren't trivially copyable with the old implementation and are now trivially copyable.
True, it is a breaking change for classes relying on an implementation provided default constructor. I'm having a hard time deciding where this matters outside of `is_trivially_default_constructible`. The only case I could think of is full initialization of a const object, but it fails in those cases now as it was failing before (hopefully this will change one day).
This is off-topic anyway.
It isn't. We're discussing whether noncopyable is or should be trivially copyable, and the decision on that defect report determines whether the current implementation is.
As I see it, since trivially copyable does not imply copyable, it is irrelevant for `noncopyable`. Even when it sounds funny.
Incidentally, the compilers I tried give 0 for is_trivial and is_trivially_copyable. They don't seem enlightened.
Only libc++ implements `is_trivially_copyable` (msvc pretends to but does a bad bad thing). See http://melpon.org/wandbox/permlink/BXhRw5DN8RhnNPw6 for a working example.
I disagree. The new implementation does not interfere with things other than copyability.
"Does not interfere" is not the same as "is better than".
I see "does not interfere" as "better than", because it means I don't have to go and implement my own version that does only what it's supposed to do. Whether this matters, I don't know. I wouldn't use `noncopyable` in C++11 code, and I stopped using it in C++03 code a long time ago because it would result in "error: undefined reference for blablabla" with absolutely no context on whether the copy attempt happens (not entirely `noncopyable`'s fault, but enough to make it useless for me). Regards, -- Agustín K-ballo Bergé.- http://talesofcpp.fusionfenix.com
Agustín K-ballo Bergé wrote:
And, while I can grudgingly accept the argument that the class deriving from noncopyable needs to decide whether to be trivially constructible or not, in this case, it is not that class that makes the decision. All classes deriving from noncopyable weren't trivially copyable with the old implementation and are now trivially copyable.
True, it is a breaking change for classes relying on an implementation provided default constructor.
Huh. I must be missing something. The default constructor does not affect trivial-copyability: A trivially copyable class is a class that: — has no non-trivial copy constructors (12.8), — has no non-trivial move constructors (12.8), — has no non-trivial copy assignment operators (13.5.3, 12.8), — has no non-trivial move assignment operators (13.5.3, 12.8), and — has a trivial destructor (12.4). It only affects triviality: A trivial class is a class that has a trivial default constructor (12.1) and is trivially copyable.
I'm having a hard time deciding where this matters...
Perhaps not. After all, I was arguing that close to zero current uses of noncopyable are trivial. But you and Andrey were arguing the opposite, that making 'noncopyable' trivial is a feature. So... does it matter or does it not? :-)
As I see it, since trivially copyable does not imply copyable, it is irrelevant for `noncopyable`. Even when it sounds funny.
It would be irrelevant in a world in which all code carefully guards its is_trivially_copyable checks with is_copy_constructible. This is not that world. But even if we constrain ourselves to abstract theory... what meaning do you give to TriviallyCopyable & ~Copyable? What does it imply?
Whether this matters, I don't know. I wouldn't use `noncopyable` in C++11 code, and I stopped using it in C++03 code a long time ago because it would result in "error: undefined reference for blablabla" with absolutely no context on whether the copy attempt happens (not entirely `noncopyable`'s fault, but enough to make it useless for me).
Interesting. Why would the copy being private not result in a compile-time error?
On 21/08/2014 01:00 p.m., Peter Dimov wrote:
Agustín K-ballo Bergé wrote:
And, while I can grudgingly accept the argument that the class deriving > from noncopyable needs to decide whether to be trivially constructible > or not, in this case, it is not that class that makes the decision. All > classes deriving from noncopyable weren't trivially copyable with the > old implementation and are now trivially copyable.
True, it is a breaking change for classes relying on an implementation provided default constructor.
Huh. I must be missing something. The default constructor does not affect trivial-copyability: It only affects triviality:
I'm having a hard time deciding where this matters...
Perhaps not. After all, I was arguing that close to zero current uses of noncopyable are trivial. But you and Andrey were arguing the opposite, that making 'noncopyable' trivial is a feature. So... does it matter or does it not? :-)
That comment was about a trivial default constructor only. I fail to imagine a case where one has a default-constructible noncopyable thingy, and whether that constructor is trivial or not matters other than for the trait. In any case, I may have misrepresented my position. I do not know about what the common use cases of `noncopyable` are, and I'm not a user myself. My point is simply that trivially copyable is an orthogonal thing to copyable today, so `noncopyable` should not be concerned with it. If it turns out the definition of trivially copyable is wrong and it's changed, then `noncopyable` will be benefit from that change transparently.
As I see it, since trivially copyable does not imply copyable, it is irrelevant for `noncopyable`. Even when it sounds funny.
It would be irrelevant in a world in which all code carefully guards its is_trivially_copyable checks with is_copy_constructible. This is not that world.
I can't really argue about the potential for misuse of the language.
But even if we constrain ourselves to abstract theory... what meaning do you give to TriviallyCopyable & ~Copyable? What does it imply?
Strictly speaking it implies TriviallyDestructible, which matters for example if you decide to have a specialization for a wrapper class for TriviallyCopyable types and let all special member functions be implicit. In that case for `noncopyable` you get a trivially destructible wrapper, while any attempt to copy or move it results in a compilation error. I have some low-level optimizations in mind as well, but I don't dare say they are fully conformant yet. I need to investigate more.
Whether this matters, I don't know. I wouldn't use `noncopyable` in C++11 code, and I stopped using it in C++03 code a long time ago because it would result in "error: undefined reference for blablabla" with absolutely no context on whether the copy attempt happens (not entirely `noncopyable`'s fault, but enough to make it useless for me).
Interesting. Why would the copy being private not result in a compile-time error?
Why indeed? I guess it would have been a compiler bug, so it would be fair for me to strike the "entirely" from my comment above. In any case, the end result was the same, after repeated occurrences of these unhelpful error messages I just replaced it with forcing compile time error messages where I could. Regards, -- Agustín K-ballo Bergé.- http://talesofcpp.fusionfenix.com
Agustín K-ballo Bergé wrote:
My point is simply that trivially copyable is an orthogonal thing to copyable today, so `noncopyable` should not be concerned with it.
That view seems academic. As a practical matter, noncopyable should very much be concerned with trivial copyability. If classes derived from noncopyable have to not be trivially copyable, then noncopyable should be defined in a way that would make them not trivially copyable. Stated differently, the meaning of "X: private noncopyable" is not tied to the language definition of 'copyable' circa 2011. The 'copyable' term in 'noncopyable' is not the same as the 'copyable' term in C++11. Stated as yet differently, if the typical user who says "X: private noncopyable" wants to imply by that that X is not trivially copyable, then noncopyable ought to be defined in a way that makes X not trivially copyable.
I can't really argue about the potential for misuse of the language.
This is not misuse. It is a correct literal interpretation of the standard. If a class is trivially copyable, I can copy it with memcpy and get a copy. That's what trivially copyable means. We can be literal and we can be pragmatic, but switching from one to the other is not a consistent position.
But even if we constrain ourselves to abstract theory... what meaning do you give to TriviallyCopyable & ~Copyable? What does it imply?
Strictly speaking it implies TriviallyDestructible, which matters for example if you decide to have a specialization for a wrapper class for TriviallyCopyable types and let all special member functions be implicit. In that case for `noncopyable` you get a trivially destructible wrapper, while any attempt to copy or move it results in a compilation error.
That's not what I had in mind when I asked. I'm asking what it means - logically - for a type to be trivially copyable but not copy constructible; not what follows from the language definition, because I know that, but what are the intended properties of the class, or in other words, why would you design one. Not being copy constructible means that the class should not be copied. Being trivially copyable means that the class bytes can be copied with memcpy and the language guarantees that the result is a proper copy of the object. What is the intersection of these two? Who needs to design such a thing?
Interesting. Why would the copy being private not result in a compile-time error?
Why indeed? I guess it would have been a compiler bug, ...
The only case that comes to mind is when you copy the class inside its own member function. Which is, I suppose, a legitimate example in which a deleted copy is better than a private undefined one.
On 21/08/2014 03:26 p.m., Peter Dimov wrote:
Agustín K-ballo Bergé wrote:
I can't really argue about the potential for misuse of the language.
This is not misuse. It is a correct literal interpretation of the standard. If a class is trivially copyable, I can copy it with memcpy and get a copy. That's what trivially copyable means.
We can be literal and we can be pragmatic, but switching from one to the other is not a consistent position.
You got me there, I live somewhere in between those worlds. I see trivially copyable as a permission to use memcpy/memmove to replace what would be a copy/move-construction, copy/move-assignment, and other operations derived from them (say swap) **if** the corresponding special member is provided and accessible. You are correct that this does not fit a strict view of either position.
Interesting. Why would the copy being private not result in a > compile-time error?
Why indeed? I guess it would have been a compiler bug, ...
The only case that comes to mind is when you copy the class inside its own member function. Which is, I suppose, a legitimate example in which a deleted copy is better than a private undefined one.
This particular behavior happened in some old MSVC version (2005 or 2008 I'd say). I no longer have access to those, and a quick check on more recent versions does not show the issue. It was likely a compiler bug fixed since then, I particularly remember 2005 skipping access control in certain scenarios. Regards, -- Agustín K-ballo Bergé.- http://talesofcpp.fusionfenix.com
Agustín K-ballo Bergé wrote:
I see trivially copyable as a permission to use memcpy/memmove to replace what would be a copy/move-construction, copy/move-assignment, and other operations derived from them (say swap) **if** the corresponding special member is provided and accessible.
If you never use is_trivially_copyable alone and always qualify it with && is_copy_constructible, I can see why you wouldn't mind is_trivially_copyable<X> to be true while is_copy_constructible<X> to be false. But the other side of the coin is that in this case you simply do not care about what is_trivially_copyable returns. So there is no reason to object if is_trivially_copyable returns false for noncopyable types. Of course... you will counter that your uses of is_trivially_copyable are sometimes qualified not by is_copy_constructible, but by is_move_constructible. I admit that it is in principle possible for a trivially copyable, but noncopyable, type to have an accessible move constructor. Specific examples elude me as usual. :-)
2014-08-21 19:37 GMT+04:00 Agustín K-ballo Bergé
Whether this matters, I don't know. I wouldn't use `noncopyable` in C++11 code, and I stopped using it in C++03 code a long time ago because it would result in "error: undefined reference for blablabla" with absolutely no context on whether the copy attempt happens (not entirely `noncopyable`'s fault, but enough to make it useless for me).
Let me add my 0.02 kopeck: * deleted functions produce much more readable error reports * defaulted functions are noexcept and that matters for traits (is_nothrow_constructible, is_trivial...) * defaulted functions are simpler to optimize for compiler * noncopyable class is widely used, optimizing and improving it will improve all the Boost's and user's code. -- Best regards, Antony Polukhin
Antony Polukhin wrote:
* deleted functions produce much more readable error reports
I wonder. Can you please give an example of these improved errors? I don't see much difference on a simple example w/ MSVC 2013.
* defaulted functions are noexcept
This is a good point. Yes, we could add 'noexcept', but if we're making changes, why not =default instead. (Because ugly #ifdefs and compiler bugs, but, well.)
2014-08-21 20:18 GMT+04:00 Peter Dimov
Antony Polukhin wrote:
* deleted functions produce much more readable error reports
I wonder. Can you please give an example of these improved errors? I don't see much difference on a simple example w/ MSVC 2013.
Without `=deleted`: noncopyable_compile_fail.cpp:32:34: note: synthesized method ‘{anonymous}::DontTreadOnMe::DontTreadOnMe(const {anonymous}::DontTreadOnMe&)’ first required here DontTreadOnMe object2(object1); ^ In file included from ../../../boost/noncopyable.hpp:15:0, from noncopyable_compile_fail.cpp:13: ../../../boost/core/noncopyable.hpp: In member function ‘{anonymous}::DontTreadOnMe& {anonymous}::DontTreadOnMe::operator=(const {anonymous}::DontTreadOnMe&)’: ../../../boost/core/noncopyable.hpp:39:20: error: ‘boost::noncopyable_::noncopyable& boost::noncopyable_::noncopyable::operator=(const boost::noncopyable_::noncopyable&)’ is private noncopyable& operator=( const noncopyable& ); With `=deleted`: noncopyable_compile_fail.cpp:32:34: error: use of deleted function ‘{anonymous}::DontTreadOnMe::DontTreadOnMe(const {anonymous}::DontTreadOnMe&)’ DontTreadOnMe object2(object1); ^ noncopyable_compile_fail.cpp:21:11: note: ‘{anonymous}::DontTreadOnMe::DontTreadOnMe(const {anonymous}::DontTreadOnMe&)’ is implicitly deleted because the default definition would be ill-formed: class DontTreadOnMe : private boost::noncopyable With GCC use of deleted function reported as an error right at the first line, while without `=deleted` more text must be looked through. * defaulted functions are noexcept
This is a good point. Yes, we could add 'noexcept', but if we're making changes, why not =default instead. (Because ugly #ifdefs and compiler bugs, but, well.)
Because as a benefit we get better results for `is_trivial` and `is_trivially_constructible` traits. Hard choice between functionality+performance and ugliness... -- Best regards, Antony Polukhin
Antony Polukhin wrote:
Because as a benefit we get better results for `is_trivial` and `is_trivially_constructible` traits.
As already mentioned, I'm not that keen on noncopyable being is_trivial which implies is_trivially_copyable. The rest of the argument could go either way but I have certain trouble with the view that noncopyable being trivially copyable could be described as 'better' with a straight face.
[Agustín K-ballo Bergé]
Only libc++ implements `is_trivially_copyable` (msvc pretends to but does a bad bad thing).
Sorry, we thought it was a synonym of is_trivially_copy_constructible! This was 95% fixed in VS14 CTP1 - we now invoke a compiler hook, which has been fixed to report accurate answers for most types. (In particular, volatility is correctly detected as nontrivial.) There are some corner cases with deleted/defaulted/etc. member functions that will be much harder to fix in the compiler, tracked by an active bug. STL
On 21/08/2014 02:15 p.m., Stephan T. Lavavej wrote:
[Agustín K-ballo Bergé]
Only libc++ implements `is_trivially_copyable` (msvc pretends to but does a bad bad thing).
Sorry, we thought it was a synonym of is_trivially_copy_constructible! This was 95% fixed in VS14 CTP1 - we now invoke a compiler hook, which has been fixed to report accurate answers for most types. (In particular, volatility is correctly detected as nontrivial.) There are some corner cases with deleted/defaulted/etc. member functions that will be much harder to fix in the compiler, tracked by an active bug.
I'm glad this was taken care of! Thank you for your good work. Regards, -- Agustín K-ballo Bergé.- http://talesofcpp.fusionfenix.com
On 08/21/2014 06:08 AM, Peter Dimov wrote:
John Maddock wrote:
1) Why on earth is:
BOOST_CONSTEXPR noncopyable() = default;
Better than
noncopyable() {}
I can tell you what's the difference, but not why it's better. :-)
constexpr on the constructor enables noncopyable, and its descendants, to be statically initialized. I suppose this makes sense; a mutex, for example, is noncopyable but it may be desirable for it to support static initialization. <snip>
I'm pretty sure that the BOOST_CONSTEXPR here is spurious. If a defaulted constructor can be constexpr, it is, and you don't have to say it. So: noncopyable() = default; ... is sufficient. And IIRC, that was a late change, so there *may* be compilers that get this wrong. But that I don't know.
John Maddock
There's a problem with noncopyable and boost::unit_test::singleton in Intel 13 for Linux in C++11 compatibility mode that's rippling through many Boost libs. To list a few:
[...]
Finally, I note that comments on Github are all very well, but many interested parties may miss the discussion altogether - we're all guilty of this I realise - but it's important not to forget the mailing list - so many thanks to Joaquin for raising this to wider awareness!
Hi, Although there's been a lively discussion on this issue, fact is it remains unsolved :-/ IMHO any fix is better than no fix. Best, Joaquín M López Muñoz Telefónica
On Thu, Sep 11, 2014 at 5:37 PM, Joaquin M Lopez Munoz
John Maddock
writes: There's a problem with noncopyable and boost::unit_test::singleton in Intel 13 for Linux in C++11 compatibility mode that's rippling through many Boost libs. To list a few:
[...]
Finally, I note that comments on Github are all very well, but many interested parties may miss the discussion altogether - we're all guilty of this I realise - but it's important not to forget the mailing list - so many thanks to Joaquin for raising this to wider awareness!
Hi,
Although there's been a lively discussion on this issue, fact is it remains unsolved :-/ IMHO any fix is better than no fix.
The fix was committed, the macro BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS is defined for Intel <= 13.10. Did it not help? If so, what is the compiler error?
Andrey Semashev
On Thu, Sep 11, 2014 at 5:37 PM, Joaquin M Lopez Munoz
Hi,
Although there's been a lively discussion on this issue, fact is it remains unsolved :-/ IMHO any fix is better than no fix.
The fix was committed, the macro BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS is defined for Intel <= 13.10. Did it not help? If so, what is the compiler error?
Sorry, my bad, I was looking at the master branch. Develop branch seems to be working OK. Thank you, Joaquín M López Muñoz Telefónica
On Thursday 11 September 2014 15:10:04 Joaquin M Lopez Munoz wrote:
Andrey Semashev
writes: On Thu, Sep 11, 2014 at 5:37 PM, Joaquin M Lopez Munoz
Hi,
Although there's been a lively discussion on this issue, fact is it remains unsolved :-/ IMHO any fix is better than no fix.
The fix was committed, the macro BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS is defined for Intel <= 13.10. Did it not help? If so, what is the compiler error?
Sorry, my bad, I was looking at the master branch. Develop branch seems to be working OK.
Perhaps, it's time to merge Boost.Config to master?
participants (8)
-
Agustín K-ballo Bergé
-
Andrey Semashev
-
Antony Polukhin
-
Eric Niebler
-
Joaquin M Lopez Munoz
-
John Maddock
-
Peter Dimov
-
Stephan T. Lavavej