The following declaration fails in clang 3.8.1 but seems to compile without error in other compilers tested (e.g. gcc 6.1, MSVC 2015, clang 3.9.1).
constexpr std::integral_constant<int,0> myConstant;
clang 3.8.1 gives:
error: default initialization of an object of const type 'const std::integral_constant<int, 0>' without a user-provided default constructor
constexpr std::integral_constant<int,0> myConstant;
Whereas the following compiles correctly in all compilers tested:
constexpr std::integral_constant<int,0> myConstant = {};
What is going on here? (is the clang 3.8.1 error correct?)
If I define my own type, should I write a user-provided default ctor so that users can avoid typing ={} ?
constexpr variables must be initialized. A declaration of the form Typename variablename; will perform default initialization on variablename.
Types which do not have a trivial default constructor will, under default initialization, be uninitialized. Normally that's fine.
But constexpr variables are not permitted to be uninitialized. Therefore, for types with trivial default constructors, you have to visibly initialize them. By doing = {} to the variable, you are causing it to be value initialized, which will zero out the object.
This should not be considered a problem. In general, you should always visibly initialize a constexpr variable, even if it's just with = {}. That way, it's clear to everybody what you're doing.
And no, you should not add default constructors to types just so that people can make constexpr variables of them without visibly initializing them. You should only add a user-provided default constructor to a type if the type needs one to do its job.
As for the compiler behavior, that's on them. Clang's behavior in 3.8.1 is correct with regard to the specification, so the others are incorrect.
According to this answer: https://stackoverflow.com/a/28338265/2013747, whether ={} is needed is an open issue that clang and gcc originally chose to implement differently. Allowing ={} to be omitted appears to be the direction that is preferred by the CWG, and clang 3.9 changed policy to reflect that.
Quoting CWG active issue #253:
253. Why must empty or fully-initialized const objects be initialized?
[]
Paragraph 9 of 8.6 [dcl.init] says:
If no initializer is specified for an object, and the object is of (possibly >cv-qualified) non-POD class type (or array thereof), the object shall be >default-initialized; if the object is of const-qualified type, the underlying >class type shall have a user-declared default constructor. Otherwise, if no >initializer is specified for an object, the object and its subobjects, if any, >have an indeterminate initial value; if the object or any of its subobjects are >of const-qualified type, the program is ill-formed.
What if a const POD object has no non-static data members? This wording requires an empty initializer for such cases [...]
(Emphasis added.) The conclusion here is that for compatibility with older compilers, and strict adherence to the standard, ={} must be used unless there is a user-declared default ctor.
The old clang behavior resulted from the above conservative interpretation
of the language specification. CWG August 2011 meeting resolved:
Notes from the August, 2011 meeting:
If the implicit default constructor initializes all subobjects, no initializer should be required.
Source: http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#253
As far as I know, this change has not yet been incorporated into any version of the C++ standard. Therefore, while omitting ={} will likely continue to compile, and may in future be officially supported by the standard, it is not currently part of the official ISO standard.
Related
I have read a few (pesudo) implementions of std::move(). And all are just casting away the reference of the parameter and then returning it as a rvalue reference.
It doesn't do anything more than that.
However, I am curious:
1. whether it does more than that.
2. whether standard explicitly states that so that the caller should be aware the side effect.
In the book The C++ Programming Language 4th edition, it states "move(x) marks x for destruction so that move(x) should be used with care".
Does it mean that there is a side effect imposed by the standard and so compiler can do certain optimization?
Thanks in advance.
Yes, that's exactly as it is described in the standard. In N4659 (which is last draft I found)
it says in §23.2.5
template <class T> constexpr remove_reference_t<T>&& move(T&& t) noexcept;
Returns: static_cast<remove_reference_t<T>&&>(t)
It doesn't mark anything for destruction, and it doesn't change the object but object may be changed in function that accepts rvalue (such as move constructor, move assignment operator)
Yes, std::move is a bit of a misnomer as it doesn't actually move anything. It is used to indicate that an object may be "moved from".
It does this by casting the object to a T&&. cppreference states the return value is static_cast<typename std::remove_reference<T>::type&&>(t). (btw, that is exactly what VS2017 does)
I don't know precisely what the standard says on the matter.
This is my code :
int x=65;
char ch{x};
And this is the warning when compiled with `-std=C++11 flag:
Narrowed conversion from "int to char"
But I think there should be an error as x is not a constant and we are initializing ch with a non-constant value. What actually happens?
You're right that the standard treats this as an error, and allows implementations to flat out reject this code.
However, implementations are almost never required to reject code that does not conform to the standard. They have to diagnose the problem, but if they attach the label "warning" to it and continue to accept the code, there is no problem.
In this case, C++11 made perfectly well-formed C++03 code into an error (not entirely your code, but char ch[] = {x}; used to be valid), so compilers have a good reason to treat it as only a warning: they want to accept as much formerly valid code as reasonable, or users might have a good reason to switch to another compiler.
clang will give you an error:
main.cpp:23:9: error: non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list [-Wc++11-narrowing]
gcc as far as I remember decided to issue warning as there is too many source code that would be broken by such decision.
when you initialize variable using uniform initialization then narrowing conversions are forbidden.
I've inherited a C++98 codebase which has two major uses of memset() on C++ classes, with macros expanded for clarity:
// pattern #1:
Obj o;
memset(&o, 0, sizeof(o));
// pattern #2:
// (elsewhere: Obj *o;)
memset(something->o, 0, sizeof(*something->o));
As you may have guessed, this codebase does not use STL or otherwise non-POD classes. When I try to put as little as an std::string into one of its classes, bad things generally happen.
It was my understanding that these patterns could be rewrited as follows in C++11:
// pattern #1
Obj o = {};
// pattern #2
something->o = {};
Which is to say, assignment of {} would rewrite the contents of the object with the default-initialized values in both cases. Nice and clean, isn't it?
Well, yes, but it doesn't work. It works on *nix systems, but results in fairly inexplicable results (in essence, garbage values) when built with VS2013 with v120_xp toolset, which implies that my understanding of initializer lists is somehow lacking.
So, the questions:
Why didn't this work?
What's a better way to replace this use of memset that ensures that members with constructors are properly default-initialized, and which can preferably be reliably applied with as little as search-and-replace (there are unfortunately no tests). Bonus points if it works on pre-VS2013.
The behavior of brace-initialization depends on what kind of object you try to initialize.
On aggregates (e.g. simple C-style structures) using an empty brace-initializer zero-initializes the aggregate, i.e. it makes all members zero.
On non-aggregates an empty brace-initializer calls the default constructor. And if the constructor doesn't explicitly initialize the members (which the compilers auto-generated constructor doesn't) then the members will be constructed but otherwise uninitialized. Members with their own constructors that initialize themselves will be okay, but e.g. an int member will have an indeterminate value.
The best way to solve your problems, IMO, is to add a default constructor (if the classes doesn't have it already) with an initializer list that explicitly initializes the members.
It works on *nix systems, but results in fairly inexplicable results (in essence, garbage values) when built with VS2013 with v120_xp toolset, which implies that my understanding of initializer lists is somehow lacking.
The rules for 'default' initialization have changed from version to version of C++, but VC++ has stuck with the C++98 rules, ignoring even the updates from C++03 I think.
Other compilers have implemented new rules, with gcc at one point even implementing some defect resolutions that hadn't been accepted for future inclusion in the official spec.
So even though what you want is guaranteed by the standard, for the most part it's probably best not to try to rely on the behavior of initialization of members that don't have explicit initializers.
I think placement new is established enough that it works on VS, so you might try:
#include <new>
new(&o) T();
new(something->p) T();
Make sure not to do this on any object that hasn't been allocated and destructed/uninitialized first! (But it was pointed out below that this might fail if a constructor throws an exception.)
You might be able to just assign from a default object, that is, o = T(); or *(something->p) = T();. A good general strategy might be to give each of these POD classes a trivial default constructor with : o() in the initializer-list.
I have a class that's using an std::discrete_distribution which can take an std::initializer_list OR a couple of iterators. My class is in some ways wrapping the discrete_distribution so I really wanted to mimic the ability to take an std::initializer_list which would then be passed down.
This is simple.
However, the std::initializer_list will always be constructed through some unknown values. So, if it was just a std::discrete_distribution I would just construct from iterators of some container. However, for me to make that available via my class, I would need to templatize the class for the Iterator type.
I don't want to template my class because it's only occasionally that it would use the initializer_list, and the cases where it doesn't, it uses an std::uniform_int_distribution which would make this template argument, maybe confusing.
I know I can default the template argument, and I know that I could just define only vector::iterators if I wanted; I'd just rather not.
According to the documentation, std::initializer_list cannot be non-empty constructed in standard C++. BTW, it is the same for C stdarg(3) va_list (and probably for similar reasons, because variadic function argument passing is implementation specific and generally has its own ABI peculiarities; see however libffi).
In GCC, std::initializer_list is somehow known to the C++ compiler (likewise <stdarg.h> uses some builtin things from the C compiler), and has special support.
The C++11 standard (more exactly its n3337 draft, which is almost exactly the same) says in §18.9.1 that std::initializer_list has only an empty constructor and refers to §8.5.4 list-initialization
You probably should use std::vector and its iterators in your case.
As a rule of thumb and intuitively, std::initializer_list is useful for compile-time known argument lists, and if you want to handle run-time known arguments (with the "number" of "arguments" unknown at compile time) you should provide a constructor for that case (either taking some iterators, or some container, as arguments).
If your class has a constructor accepting std::initializer_list<int> it probably should have another constructor accepting std::vector<int> or std::list<int> (or perhaps std::set<int> if you have some commutativity), then you don't need some weird templates on iterators. BTW, if you want iterators, you would templatize the constructor, not the entire class.
Now and then when using GCC I get cryptic errors like this:
undefined reference to 'vtable for classname'
When it's not caused by a missing library, this not-very-descriptive error message always causes me to dig through code files line by line to find the missing implementation for a virtual function. Is there a way to make the linker tell me which virtual function it is missing, perhaps a flag or something? Or is it maybe telling me but I don't understand what it's saying?
From gcc faq:
When building C++, the linker says my
constructors, destructors or virtual
tables are undefined, but I defined
them
The ISO C++ Standard specifies that
all virtual methods of a class that
are not pure-virtual must be defined,
but does not require any diagnostic
for violations of this rule
[class.virtual]/8. Based on this
assumption, GCC will only emit the
implicitly defined constructors, the
assignment operator, the destructor
and the virtual table of a class in
the translation unit that defines its
first such non-inline method.
Therefore, if you fail to define this
particular method, the linker may
complain about the lack of definitions
for apparently unrelated symbols.
Unfortunately, in order to improve
this error message, it might be
necessary to change the linker, and
this can't always be done.
The solution is to ensure that all
virtual methods that are not pure are
defined. Note that a destructor must
be defined even if it is declared
pure-virtual [class.dtor]/7.
The solution that I adopt is search the classname and seek virtual methods declaration and check if there is any definition. I didn't found any other solution for this.