Passing a class object with trivial copy constructor, but no output? - c++

I tried this program with GCC and Clang, but both output nothing
#include <iostream>
struct A {
A(){}
template<typename T>
A(T &) {
std::cout << "copied!";
}
};
void f(...) { }
int main() {
A a;
f(a);
}
According to my Standards reading, this program should output "copied!". Can anyone tell me whether I am mistaken or whether this is a bug in those two compilers?

It would seem that what you expect is the behavior defined by the standard.
Template functions do not prevent the creation of copy constructors/assignment operators. So template functions don't prevent a class from being considered "trivially copyable". However, they do participate in overload resolution when it comes time to actually copy them, so they can interfere. And since a in this example is a non-const l-value, it better fits the signature A(A&) than it does A(const A&). So it calls the template function.
(Though why you didn't bother to explain all of this in your question eludes me, since you obviously did your research.)
However, considering how small of a corner-case this is, I wouldn't go around relying on this behavior to force trivially copyable classes into not being trivially copied.

Related

C++11 usage of delete specifier vs private functions

I am in the process of boning up on my C++ (as in, attempting to get into more modern-style coding) and am looking at the delete specifier. It is my understanding that it is used to make sure that certain functionality cannot be defined or called. If I understand it correctly, this is primarily within the domain of assignment and copy. I am not quite sure what the difference is between using the delete specifier and just making those functions private.
For instance, what is the difference between:
class Foo {
private:
Foo& operator(const Foo&);
Foo(const Foo&);
};
And
class Bar {
public:
Bar& operator(const Bar&) = delete;
Bar(const Bar&) = delete;
};
In other words: what does using the delete specifier gain? Is it just to make things look nicer?
One obvious difference is that if you make the function private, then it is still accessible from within the class and any friends.
An explicitly deleted function is not usable anywhere, so you know simply from that one line that it's never used, without having to inspect the implementation.
You can make the function both private and deleted: then its participation in overload resolution is more consistent.
It's simpler.
This way, your intent is clearly stated and your compiler can outright say "calling this function is prohibited".
Otherwise you're relying on:
access control (for attempted calls from outside of the class), or
the linker giving you an "undefined reference" near the end of your build process. That's kind of okay for small programs where you can quickly find out what's going on, but for deep class hierarchies where some many-times-over encapsulated object cannot be copied but has not been deleted, good luck debugging that.
Short answer is: uses of a deleted function make the program ill-formed and you are notified at compile-time, uses of a function that is not defined end in an odd error that comes out of the linker.
As an example, there is a relevant part of the standard that states:
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed.
Therefore, the following compiles just fine:
struct S {
void f();
};
template<typename T, void (T::*M)() = &T::f>
void g() {}
int main() {
g<S>();
}
While the code below does not:
struct S {
void f() = delete;
};
template<typename T, void (T::*M)() = &T::f>
void g() {}
int main() {
g<S>();
}
That's because in the second case the code is ill-formed and you have a compile-time error in any case, no matter if you are going to use or not M. In the second case, you get an error out of the linker only if you try to use it:
template<typename T, void (T::*M)() = &T::f>
void g() {
T t;
(t.*M)();
}
Of course, compile-time errors are much better to prevent issues. The example uses public functions, but making them private doesn't prevent from using them within the class in similar ways. That's just a toy example to show a possible difference.

Why are mutexes and condition variables trivially copyable?

LWG 2424 discusses the undesirable status of atomics, mutexes and condition variables as trivially copyable in C++14. I appreciate that a fix is already lined up, but std::mutex, std::condition variable et al. appear to have non-trivial destructors. For example:
30.4.1.2.1 Class mutex [thread.mutex.class]
namespace std {
class mutex {
public:
constexpr mutex() noexcept;
~mutex(); // user-provided => non-trivial
…
}
}
Shouldn't this disqualify them as trivially copyable?
Either it was my mistake, or I was misquoted, and I honestly don't recall which.
However, I have this very strongly held advice on the subject:
Do not use is_trivial nor is_trivially_copyable! EVER!!!
Instead use one of these:
is_trivially_destructible<T>
is_trivially_default_constructible<T>
is_trivially_copy_constructible<T>
is_trivially_copy_assignable<T>
is_trivially_move_constructible<T>
is_trivially_move_assignable<T>
Rationale:
tldr: See this excellent question and correct answer.
No one (including myself) can remember the definition of is_trivial and is_trivially_copyable. And if you do happen to look it up, and then spend 10 minutes analyzing it, it may or may not do what you intuitively think it does. And if you manage to analyze it correctly, the CWG may well change its definition with little or no notice and invalidate your code.
Using is_trivial and is_trivially_copyable is playing with fire.
However these:
is_trivially_destructible<T>
is_trivially_default_constructible<T>
is_trivially_copy_constructible<T>
is_trivially_copy_assignable<T>
is_trivially_move_constructible<T>
is_trivially_move_assignable<T>
do exactly what they sound like they do, and are not likely to ever have their definition changed. It may seem overly verbose to have to deal with each of the special members individually. But it will pay off in the stability/reliability of your code. And if you must, package these individual traits up into a custom trait.
Update
For example, clang & gcc compile this program:
#include <type_traits>
template <class T>
void
test()
{
using namespace std;
static_assert(!is_trivial<T>{}, "");
static_assert( is_trivially_copyable<T>{}, "");
static_assert( is_trivially_destructible<T>{}, "");
static_assert( is_destructible<T>{}, "");
static_assert(!is_trivially_default_constructible<T>{}, "");
static_assert(!is_trivially_copy_constructible<T>{}, "");
static_assert( is_trivially_copy_assignable<T>{}, "");
static_assert(!is_trivially_move_constructible<T>{}, "");
static_assert( is_trivially_move_assignable<T>{}, "");
}
struct X
{
X(const X&) = delete;
};
int
main()
{
test<X>();
}
Note that X is trivially copyable, but not trivially copy constructible. To the best of my knowledge, this is conforming behavior.
VS-2015 currently says that X is neither trivially copyable nor trivially copy constructible. I believe this is wrong according to the current spec, but it sure matches what my common sense tells me.
If I needed to memcpy to uninitialized memory, I would trust is_trivially_copy_constructible over is_trivially_copyable to assure me that such an operation would be ok. If I wanted to memcpy to initialized memory, I would check is_trivially_copy_assignable.
Not all implementations provide a nontrivial destructor for mutex. See libstdc++ (and assume that __GTHREAD_MUTEX_INIT has been defined):
// Common base class for std::mutex and std::timed_mutex
class __mutex_base
{
// […]
#ifdef __GTHREAD_MUTEX_INIT
__native_type _M_mutex = __GTHREAD_MUTEX_INIT;
constexpr __mutex_base() noexcept = default;
#else
// […]
~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); }
#endif
// […]
};
/// The standard mutex type.
class mutex : private __mutex_base
{
// […]
mutex() noexcept = default;
~mutex() = default;
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete;
};
This implementation of mutex is both standard conforming and trivially copyable (which can be verified via Coliru). Similarly, nothing stops an implementation from keeping condition_variable trivially destructible (cf. [thread.condition.condvar]/6, although I couldn't find an implementation that does).
The bottom line is that we need clear, normative guarantees, and not clever, subtle interpretations of what condition_variable does or doesn't have to do (and how it has to accomplish that).
It's important to look at this from a language lawyer perspective.
It's basically impossible for an implementation to implement mutex, condition variables, and the like in a way that leaves them trivially copyable. At some point, you have to write a destructor, and that destructor is very likely going to have to do non-trivial work.
But that doesn't matter. Why? Because the standard does not explicitly state that such types will not be trivially copyable. And therefore it is, from the perspective of the standard, theoretically possible for such objects to be trivially copyable.
Even though no functional implementation every can be, the point of N4460 is to make it very clear that such types will never be trivially copyable.

Reference qualifiers and deleted member methods

Consider the following code:
#include<utility>
struct S {
void f(int) = delete;
void f(int) && { }
};
int main() { }
It doesn't compile saying that the member method cannot be overloaded and it makes sense, of course.
On the other side, the following code compiles:
#include<utility>
struct S {
void f(int) & = delete;
void f(int) && { }
};
int main() {
S s;
// s.f(42); <-- error, deleted member method
std::move(s).f(42);
}
Is that legal code?
Wouldn't it be possible to define two completely different interfaces within the same class, the former to be used with lvalues, the latter with rvalues?
Apart from the fact that it doesn't make much sense, but it really hurts me.
Shouldn't a deleted function be deleted as a whole, instead of deleted only if you are a lvalue?
Which is the purpose of this feature? Is it the classic obscure corner case or is there something more I can't see?
Sometimes it makes sense to prohibit certain operations if object is l- or r-value.
Imagine RAII wrapper for FILE*. It opens file in constructor, closes it in destructor, turning C feature requiring manual control to C++ exception-safe class. To interact with C interface, there is a .get() member which returns raw pointer. Someone might write:
FILE* file = CFile("file.txt").get();
It would compile, but it is wrong: file would be closed as soon, as file variable would be initialized. If you delete an r-value overload (on never provide it in the first place), then it would lead to compile-time error and save us from bug-hunting.

Error "recursive on all control paths" when copy constructor is used and virtual function present

The error below is confusing me. Here is a short piece of a much more complicated code. It appears strange to me, that only the existence of both a templated constructor and a virtual method cause an error, and only when copy-initializing an object.
Does anyone have an idea? Thanks.
class A
{
long *p;
public:
A():p(0)
{
}
template<class T>
A(T val):p(val)// 1
{
}
operator long*()
{
return p;
}
};
class B
{
virtual void f()// 2
{
}
};
class C : public A, public B
{
};
void main()
{
C c;
The next line in main() is
A a=c;
and this triggers the error below if both the lines marked // 1 and // 2 are present:
warning C4717: 'C::C' : recursive on all control paths, function will cause runtime stack overflow
But when the following is used in main(), there is no error:
A a;
a=c;
}
What you have is a nasty confluence of copy elision and a constructor that makes a copy of the parameter.
First, let's clear up a misunderstanding: A a = c; is not equivalent to A a; a = c;. The first calls the copy ctor, the second calls the assignment operator. See for yourself using this code sample.
The constructor A::A<T>(T) could make a copy of T whenever it is called. Unfortunately, if you call it using an A parameter (or in your example C, which is-a A), the parameter will attempt to copy itself, which calls A::A<T>(T) again, which copies itself again, and again... until stack overflow.
Why doesn't this happen when you don't have the virtual void f() in B? This is a side effect of copy elision, which is an implementation-dependent feature. Having the virtual method there might have been enough for visual studio to decide not to elide the copy, but in any case you shouldn't depend on it. This is why you are strongly advised not to have observable side-effects for copy ctors.
Just in case you were looking for a solution, you can remove the copy by changing A::A<T>(T) to take a reference, like A::A<T>(T&). Even better, take a const T& because this helps ensure that there are no side effects in the ctor (as you can't modify the T).
A a=c; // this results in A::A(C c) template constructor instantiation.
After that it is recursion since to make a copy, you need to make a copy, you need to make a copy.... :)
For proper usage refer this.

Friending classes defined in the std namespace: any guarantees?

This question came up as I answered this question: does the standard allow and make any guarantees about friend-ing standard library classes and/or functions?
In this particular case, the situation the question was whether:
class MyUserDefinedType
{
friend struct std::default_delete<MyUserDefinedType>;
private:
~MyUserDefinedType() { }
}
is guaranteed to allow MyUserDefinedType to be stored in a std::unique_ptr<MyUserDefinedType> or std::shared_ptr<MyUserDefinedType> object with the default deleter.
In general, are classes described in the standard library required to implement their functionality directly, or can they use any arbitrary level of indirection? For example, is it possible that
std::default_delete<MyUserDefinedType> is actually a using alias of a class defined in an inner namespace of std, in which case the friend declaration would be illegal
or
std::default_delete<MyUserDefinedType> calls some other class that actually does the deleting, in which case the friend declaration would not have the desired effect
or something else along those lines?
My guess is that this is UB not guaranteed to work but I am curious if this is addressed specifically by the standard.
This specific example given above works for clang trunk (w/libc++) and GCC 4.7.2 (w/libstdc++), FWIW
is it possible that std::default_delete<MyUserDefinedType> is actually a using alias of a class defined in an inner namespace of std, in which case the friend declaration would be illegal?
No. Per Paragraph 20.7.1.1.2 of the C++11 Standard:
namespace std {
template <class T> struct default_delete {
constexpr default_delete() noexcept = default;
template <class U> default_delete(const default_delete<U>&) noexcept;
void operator()(T*) const;
};
}
The fact that it has to be a class template is explicitly specified. This means it cannot be an alias template. If that was the case, it would also be impossible to specialize it.
is it possible that std::default_delete<MyUserDefinedType> calls some other class that actually does the deleting, in which case the friend declaration would not have the desired effect?
Yes. Nothing in the Standard specifies that the call cannot be done by some internal helper. Per Paragraph 20.1.1.2:
void operator()(T *ptr) const;
3 Effects: calls delete on ptr.
4 Remarks: If T is an incomplete type, the program is ill-formed.
This only specifies what the effect of invoking the call operator on the default_delete<> functor should be, not how this shall be achieved concretely (whether directly inside the body of the call operator, or by delegating the task to some member function of some other class).
In general, are classes described in the standard library required to implement their functionality directly, or can they use any arbitrary level of indirection?
In general an implementation may indirect as much as it wants. Have e.g. a look at the implementations of standard containers and their iterators - or just use them wrong and see which templates are involved from the error messages. However, since default_delete is nothing magic, that should be a one-liner, you can expect it to do the work itself, but it's not guaranteed.
My guess is that this is UB but I am curious if this is addressed specifically by the standard.
It's not UB, it's just unspecified.
You could be sure if you just specialized default_delete<MyUserDefinedType> (it is allowed to specialize standard libraray templates), but I would not do that.
I would not use friendship at all, especially not if it comes to templates that have not been specialized. Consider this:
//your code
class MyUserDefinedType
{
friend struct std::default_delete<MyUserDefinedType>; //for deletion
private:
int veryPrivateData;
~MyUserDefinedType() { }
};
//evil colleague's code:
namespace std {
//we may specialize std-templates for UDTs...
template<>
struct default_delete<MyUserDefinedType>
{
constexpr default_delete() noexcept = default;
template <class U> default_delete(const default_delete<U>&) noexcept {}
void operator()(T* pt) const { delete pt; }
//sneaky...
void access(MyUserDefinedType& mudt, int i) const
{ mudt.veryPrivateData = i; }
};
}
void somewhere_deep_in_the_code()
{
MyUserDefinedType& myUDT = /*something...*/;
std::default_delete<MyUserDefinedType>().access(myUDT, 42); //tricked you!
}
Friends can do anything to you. Choose them with caution. In this case, I'd really recommend a custom deleter - assuming it makes any sense making the destructor private but providing access to it via the deleter.