Consider:
void foo() {
std::vector<std::atomic<int>> foo(10);
...
}
Are the contents of foo now valid? Or do I need to explicitly loop through and initialise them? I have checked on Godbolt and it seems fine, however the standard seems to be very confused on this point.
The std::vector constructor says it inserts default-inserted instances of std::atomic<int>, which are value initialised via placement new.
I think this effect of value initialisation applies:
2) if T is a class type with a default constructor that is neither user-provided nor deleted (that is, it may be a class with an implicitly-defined or defaulted default constructor), the object is zero-initialized and then it is default-initialized if it has a non-trivial default constructor;
So it seems to me that the atomics are zero-initialised. So the question is, does zero-initialisation of a std::atomic<int> result in a valid object?
I'm going to guess that the answer is "yes in practice but it's not really defined"?
Note: This answer agrees that it is zero-initialised, but doesn't really say if that means that the object is valid.
You are correct to be worried. According to standard the atomics has the default constructor called, however they have not been initialized as such. This is because the default constructor doesn't initialize the atomic:
The default-initialized std::atomic<T> does not contain a T object,
and its only valid uses are destruction and initialization by
std::atomic_init
This is somewhat in violation of the normal language rules, and some implementations initialize anyway (as you have noted).
That being said, I would recommend taking the extra step to make 100% sure they are initialized correctly according to standard - after all you are dealing with concurrency where bugs can be extremely hard to track down.
There are many ways to dodge the issue, including using wrapper:
struct int_atomic {
std::atomic<int> atomic_{0};//use 'initializing' constructor
};
Even if the default constructor were called (it isn't, because it's trivial) it doesn't really do anything.
Zero-initialisation obviously cannot be guaranteed to produce a valid atomic; this'll only work if by chance a valid atomic is created by zero-initialising all its members.
And, since atomics aren't copyable, you can't provide a initialisation value in the vector constructor.
You should now loop over the container and std::atomic_init each element. If you need to lock around this, that's fine because you're already synchronising the vector's creation for the same reason.
Related
Have found comparable questions but not exactly with such a case.
Take the following code for example:
#include <iostream>
#include <string>
#include <vector>
struct Inner
{
int a, b;
};
struct Outer
{
Inner inner;
};
std::vector<Inner> vec;
int main()
{
Outer * an_outer = new Outer;
vec.push_back(std::move(an_outer->inner));
delete an_outer;
}
Is this safe? Even if those were polymorphic classes or ones with custom destructors?
My concern regards the instance of "Outer" which has a member variable "inner" moved away. From what I learned, moved things should not be touched anymore. However does that include the delete call that is applied to outer and would technically call delete on inner as well (and thus "touch" it)?
Neither std::move, nor move semantics more generally, have any effect on the object model. They don't stop objects from existing, nor prevent you from using those objects in the future.
What they do is ask to borrow encapsulated resources from the thing you're "moving from". For example, a vector, which directly only stores a pointer some dynamically-allocated data: the concept of ownership of that data can be "stolen" by simply copying that pointer then telling the vector to null the pointer and never have anything to do with that data again. It's yielded. The data belongs to you now. You have the last pointer to it that exists in the universe.
All of this is achieved simply by a bunch of hacks. The first is std::move, which just casts your vector expression to vector&&, so when you pass the result of it to a construction or assignment operation, the version that takes vector&& (the move constructor, or move-assignment operator) is triggered instead of the one that takes const vector&, and that version performs the steps necessary to do what I described in the previous paragraph.
(For other types that we make, we traditionally keep following that pattern, because that's how we can have nice things and persuade people to use our libraries.)
But then you can still use the vector! You can "touch" it. What exactly you can do with it is discoverable from the documentation for vector, and this extends to any other moveable type: the constraints emplaced on your usage of a moved-from object depend entirely on its type, and on the decisions made by the person who designed that type.
None of this has any impact on the lifetime of the vector. It still exists, it still takes memory, and it will still be destructed when the time comes. (In this particular example you can actually .clear() it and start again adding data to a new buffer.)
So, even if ints had any sort of concept of this (they don't; they encapsulate no indirectly-stored data, and own no resources; they have no constructors, so they also have no constructors taking int&&), the delete "touch"ing them would be entirely safe. And, more generally, none of this depends on whether the thing you've moved from is a member or not.
More generally, if you had a type T, and an object of that type, and you moved from it, and one of the constraints for T was that you couldn't delete it after moving from it, that would be a bug in T. That would be a serious mistake by the author of T. Your objects all need to be destructible. The mistake could manifest as a compilation failure or, more likely, undefined behaviour, depending on what exactly the bug was.
tl;dr: Yes, this is safe, for several reasons.
std::move is a cast to an rvalue-reference, which primarily changes which constructor/assignment operator overload is chosen. In your example the move-constructor is the default generated move-constructor, which just copies the ints over so nothing happens.
Whether or not this generally safe depends on the way your classes implement move construction/assignment. Assume for example that your class instead held a pointer. You would have to set that to nullptr in the moved-from class to avoid destroying the pointed-to data, if the moved-from class is destroyed.
Because just defining move-semantics is a custom way almost always leads to problems, the rule of five says that if you customize any of:
the copy constructor
the copy assignment operator
the move constructor
the move assignment operator
the destructor
you should usually customize all to ensure that they behave consistently with the expectations a caller would usually have for your class.
I thought that initializing a std::optional with std::nullopt would be the same as default construction.
They are described as equivalent at cppreference, as form (1)
However, both Clang and GCC seem to treat these toy example functions differently.
#include <optional>
struct Data { char large_data[0x10000]; };
std::optional<Data> nullopt_init()
{
return std::nullopt;
}
std::optional<Data> default_init()
{
return {};
}
Compiler Explorer seems to imply that using std::nullopt will simply set the one byte "contains" flag,
nullopt_init():
mov BYTE PTR [rdi+65536], 0
mov rax, rdi
ret
While default construction will value-initialize every byte of the class. This is functionally equivalent, but almost always costlier.
default_init():
sub rsp, 8
mov edx, 65537
xor esi, esi
call memset
add rsp, 8
ret
Is this intentional behavior? When should one form be preferred over the other?
Update: GCC (since v11.1) and Clang (since v12.0.1) now treat both forms efficiently.
In this case, {} invokes value-initialization. If optional's default constructor is not user-provided (where "not user-provided" means roughly "is implicitly declared or explicitly defaulted within the class definition"), that incurs zero-initialization of the entire object.
Whether it does so depends on the implementation details of that particular std::optional implementation. It looks like libstdc++'s optional's default constructor is not user-provided, but libc++'s is.
For gcc, the unnecessary zeroing with default initialization
std::optional<Data> default_init() {
std::optional<Data> o;
return o;
}
is bug 86173 and needs to be fixed in the compiler itself. Using the same libstdc++, clang does not perform any memset here.
In your code, you are actually value-initializing the object (through list-initialization). It appears that library implementations of std::optional have 2 main options: either they default the default constructor (write =default;, one base class takes care of initializing the flag saying that there is no value), like libstdc++, or they define the default constructor, like libc++.
Now in most cases, defaulting the constructor is the right thing to do, it is trivial or constexpr or noexcept when possible, avoids initializing unnecessary things in default initialization, etc. This happens to be an odd case, where the user-defined constructor has an advantage, thanks to a quirk in the language in [decl.init], and none of the usual advantages of defaulting apply (we can specify explicitly constexpr and noexcept). Value-initialization of an object of class type starts by zero-initializing the whole object, before running the constructor if it is non-trivial, unless the default constructor is user-provided (or some other technical cases). This seems like an unfortunate specification, but fixing it (to look at subobjects to decide what to zero-initialize?) at this point in time may be risky.
Starting from gcc-11, libstdc++ switched to the used-defined constructor version, which generates the same code as std::nullopt. In the mean time, pragmatically, using the constructor from std::nullopt where it does not complicate code seems to be a good idea.
The standard doesn't say anything about the implementation of those two constructors. According to [optional.ctor]:
constexpr optional() noexcept;
constexpr optional(nullopt_t) noexcept;
Ensures:*this does not contain a value.
Remarks: No contained value is initialized. For every object type T these constructors shall be constexpr constructors (9.1.5).
It just specifies the signature of those two constructors and their "Ensures" (aka effects): after any of those constructions the optional doesn't contain any value. No other guarantees are given.
Whether the first constructor is user-defined is implementation-defined (i.e depends on the compiler).
If the first constructor is user-defined, it can of course be implemented as setting the contains flag. But a non-user-defined constructor is also compliant with the standard (as implemented by gcc), because this also zero-initialize the flag to false. Although it does result in costy zero-initialization, it doesn't violate the "Ensures" specified by the standard.
As it comes to real-life usage, well, it is nice that you have dug into the implementations so as to write optimal code.
Just as a side-note, probably the standard should specify the complexity of those two constructors (i.e O(1) or O(sizeof(T)))
Motivational example
When I write:
std::optional<X*> opt{};
(*opt)->f();//expects error here, not UB or heap corruption
I would expect the optional is initialized and doesn't contain uninitialized memory. Also I wouldn't expect a heap corruption to be a consequence since Im expecting everything is initialized fine. This compares up with the pointer semantic of std::optional:
X* ptr{};//ptr is now zero
ptr->f();//deterministic error here, not UB or heap corruption
If I write std::optional<X*>(std::nullopt) I would have hoped the same but at least here it looks more of an ambiguous situation.
The reason is Uninitialized Memory
It is very likely that this behavior is intentional.
(Im not part of any comittee so in the end I cannot say sure)
This is the primary reason: an empty brace init (zero-init) shouldn't lead to uninitialized memory (although the language doesn't enforce this as a rule) - how else will you guarentee there's no un-initialized memory in your program ?
For this task we often turn to use static analysis tools: prominently cpp core check that is based on enforcing the cpp core guidelines; in particular there's a few guidelines concerning exactly this issue. Had this not been possible our static analysis would fail for this otherwise seemingly simple case; or worse be misleading. In contrast, heap based containers do not have the same issue naturally.
Unchecked access
Remember that accessing std::optional is unchecked - this leads to the case where you could by mistake access that unitialized memory.
Just to showcase this, if that weren't the case then this could be heap corruption:
std::optional<X*> opt{};//lets assume brace-init doesn't zero-initialize the underlying object for a moment (in practice it does)
(*opt)->f();//<- possible heap corruption
With current implementation however, this becomes deterministic (seg fault/access violation on main platforms).
Then you might ask, why doesn't the std::nullopt 'specialized' constructor not initialize the memory ?
Im not really sure why it doesn't. While I guess it wouldn't be an issue if it did. In this case, as opposed to the brace-init one, it doesn't come with the same kind of expectations. Subtly, you now have a choice.
For those interested MSVC does the same.
If I have a class defined like
class A {
protected:
~A(){ }
};
then I can dynamically allocate the individual as well as array of objects like
A* ptr1 = new A;
A* ptr2 = new A[10];
However when I define the constructor for this class
class A {
public:
A(){}
protected:
~A(){ }
};
then I can create individual objects with
A* ptr = new A;
but when I try to dynamically allocate the array of object with
A* ptr = new A[10];
compiler(gcc-5.1 and Visual Studio 2015) starts complaining that A::~A() is inaccessible.
Can anyone explain about:-
1- Why is the difference in behavior with constructor being defined and not defined.
2- When the constructor is defined why I am allowed to create individual object and not array of object.
Rejecting an array-new with a protected destructor is correct, as per C++11, §5.3.4 ¶17:
If the new-expression creates an object or an array of objects of class type, access and ambiguity control are done for the allocation function, the deallocation function (12.5), and the constructor (12.1). If the new expression creates an array of objects of class type, access and ambiguity control are done for the destructor (12.4).
(emphasis added; almost exactly the same wording is used in C++03, §5.3.4 ¶16; C++14 moves some stuff around, but that doesn't seem to change the core of the issue - see #Baum mit Augen's answer)
That comes from the fact that new[] succeeds only if only all the elements have been constructed, and wants to avoid leaking objects in case one of the costructor calls fails; thus, if it manages to construct - say - the first 9 objects but the 10th fails with an exception, it has to destruct the first 9 before propagating the exception.
Notice that this restriction logically wouldn't be required if the constructor was declared as noexcept, but still the standard doesn't seem to have any exception in this regard.
So, here gcc is technically wrong in the first case, which, as far as the standard is concerned, should be rejected as well, although I'd argue that "morally" gcc does the right thing (as in practice there's no way that the default constructor of A can ever throw).
As it turns out, gcc is not correct here. In N4141 (C++14), we have:
If the
new-expression creates an array of objects of class type, the destructor is potentially invoked (12.4).
(5.3.4/19 [expr.new]) and
A
program is ill-formed if a destructor that is potentially invoked is deleted or not accessible from the context
of the invocation.
(12.4/11 [class.dtor]). So both array cases should be rejected. (Clang does get that right, live.)
The reason for that is, as mentioned by others and by my old, incorrect answer, that the construction of elements of class type can potentially fail with an exception. When that happens, the destructor of all fully constructed elements must be invoked, and thus the destructor must be accessible.
That limitation does not apply when allocating a single element with operator new (without the []), because there can be no fully constructed instance of the class if the single constructor call fails.
I'm not a language lawyer (very familiar with the standard), but suspect the answer is along the lines of that given earlier by Baum mit Augen (deleted, so only those with sufficient reputation can see it).
If the construction of subsequent array elements fails and throws an exception, then the already constructed elements will need to be deleted, requiring access to the destructor.
However, if the constructor is noexcept, this can be ruled out and access to the destructor is not required. The fact that gcc and clang both still complain even in this case, may well be a compiler bug. That is, the compiler fails to take into account that the constructor is noexcept. Alternatively, the compilers may be within the standard, in which case, this smells like a defect in the standard.
How many copies happen/object exist in the following, assuming that normal compiler optimizations are enabled:
std::vector<MyClass> v;
v.push_back(MyClass());
If it is not exactly 1 object creation and 0 copying, What can I do (including changes in MyClass) to achieve that, since it seems to me that that is all that should really be necessary?
If the constructor of MyClass has side-effects, then in C++03 the copy is not permitted to be elided. That's because the temporary object that's the source of the copy has been bound to a reference (the parameter of push_back).
If the copy constructor of MyClass has no side-effects then the compiler is permitted to optimize it away under the "as-if" rule. I think the only sensible way to determine whether it actually has done so with "normal optimizations" is to inspect the emitted code. Different people have different ideas what's normal, and a given compiler might be sensitive to the details of MyClass. My guess is that what this amounts to is whether or not the compiler (or linker) inlines everything in sight. If it does then it will probably optimize, if it doesn't then it won't. So even the size of the constructor code might be relevant, never mind what it does.
So I think the main thing you can do is to ensure that both the default and the copy constructor of MyClass have no side-effects and are available to be inlined. If they're not available then of course the compiler will assume that they could have side-effects and will do the copy. If link-time optimization is a normal compiler option for you, then you don't have to do much to make them available. Otherwise, if they're user-defined then do it in the header file that defines MyClass. You might be able to get away with the default constructor having certain kinds of side-effects: if the effects don't depend on the address of the temporary being different from the address of the vector element then "as-if" still applies.
In C++11 you have a move (that likewise must not be elided if it has side-effects), but you can use v.emplace_back() to avoid that. The move would call the move constructor of MyClass if it has one, otherwise the copy constructor, and everything I say above about "as-if" applies to moves. emplace_back() calls the no-args constructor to construct the vector element (or if you pass arguments to emplace_back then whatever constructor matches those args), which I think is exactly what you want.
You mean:
std::vector<MyClass> v;
v.push_back(MyClass());
None. The temporary will cause the move version of push_back to be called. Even the move construction will most likely be elided.
If you have a C++11 compiler, you can use emplace_back to construct the element at the end of the vector, zero copies necessary.
In C++03, you would have a construction and a copy, plus destruction of the temporary.
If your compiler supports C++11 and MyClass defines a move constructor, then you have one construction and a move.
As mentionned by Timbo, you can also use emplace_back to avoid the move, the object being constructed in-place.
Could someone please explain what is meant by the following?
You must define a default constructor if your class defines member variables and has no other constructors. Otherwise the compiler will do it for you, badly.
What are they referring to as "badly"?
From the expansion of that link:
"The reason for this is that if you
have no other constructors and do not
define a default constructor, the
compiler will generate one for you.
This compiler generated constructor
may not initialize your object
sensibly."
Might refer to how new T and new T() differ when there is no ctor provided.
It's good to be sure that the object is created in a known state. Primitive variables won't be set to zero by default, so you could end up with subtle bugs that don't always show up. By initializing the member variables to sensible variables, everything is much more predictable.
The only problem with the default constructor is that it initializes only what the compiler thinks must be initialized, and not what you may think needs to be initialized. Basically, that means that it will invoke initializers for objects with default initializers. It won't set pointers or simple types like int to sane values, etc. If that is sufficient, then the default constructor is not 'bad'. When it is insufficient, it is a bug (in your code) that you did not define the necessary default constructor with the correct initialization.
Take the Google style guide with a grain of salt -- or maybe a truckload of salt.
It is true that the compiler-generated default constructor won't necessarily initialize members that are of built-in types in a meaningful fashion. If you want that done, then yes, its failure to do that is bad. OTOH, if you don't want that done, then its doing it could be somewhat bad (wasteful) as well.
Bottom line: there are times to write your own default ctor, but they tend toward the exception, not the rule. Although there are simple rules of thumb to cover a lot of cases in C++ and will prevent a lot of problems, this really isn't one of them -- here you pretty much do need to know what the compiler-generated ctor will do, and what you want different if you're going to write your own.
In Debug build most compilers fill uninitialized space with some magic values, so that debugging is reliable. And providing custom constructor prevents certain POD optimizations.
In fact, it's a guideline just to make sure people does explicitely make the statement of what is an invalid or default state of any object.
That way, no surprise when reading the code, compared to the actual execution.
However, think that it's a company guideline, that is used to make sure everyone does follow the same rules, that's not a you-must-follow-it-because-google-does-it.
In fact, if you manage to make all your member objects being in valid state when default constructed, or force you to set a constructor, then there is no good reason for such a guideline.
If you have any primitive types as member variables (eg. int, float), then the default ctor will not initialize them. member variables that are a class type will have their default ctor's invoked.
Prefer member initializer lists, so your user supplied ctor may be empty:
class Foo {
int bar;
float baz;
Foo(): bar(0), baz(0.0f) { /* empty ctor body */ }
};
It won't set integers to 0 or pointers to null. It will run default constructors on object of types with constructors.
Some people would call it 'not sensible'.
It just seems a too simplified version of the rules of 3, you should either define yourself or leave the compiler version of
the copy constructor
the assignment operator
the destructor
(Note that by defining yourself a copy constructor, the compiler won't define a default constructor).
The default constructor built by the compiler does 'nothing', it will not even zero the memory occupied by the object