how does the default assignment operator implemented in actual stl - c++

suppose we are implementing a vector class and we do
vector v;
v={1,2,3,4};
so,here we are implementing our own vector class so,how this list pass to assignment operator as an argument how we handle it because we passing constant which are not accessible by pointer variable and reference variable.
But all this can be done in stl vector class, so how did they do?

Prior to C++17, all arguments to all functions name fully constructed objects.
A prvalue std::initialiser_list<int> object (with no name) is constructed from {1,2,3,4}, and that is the constructor's argument. That temporary object ceases to exist once v's constructor ends (specifically at the end of the full expression that creates it).
From C++17 onward, a value that will initialise an object can be passed around. We still call it a prvalue std::initialiser_list<int>, but it isn't an object (yet). Somewhere in v's initialisation, where it gets used, a std::initialiser_list<int> object is constructed. It also ceases to exist after the constructor is done.

Related

Does wrapping an lvalue in double curly braces create a temporary object that can be passed as an rvalue reference?

The following compiles on several different compilers including g++, clang, and MSVC, but I cannot figure out why:
#include <string>
class C {
std::string m;
};
void Accept(C &&);
extern C c;
int main() {
Accept({{c}});
}
The generated assembly code appears to show a call to the copy constructor of std::string before then calling Accept(), which I am assuming means that the compiler generated a call to class C's copy constructor. It therefore appears that using {{c}} as an argument to an rvalue reference parameter creates a temporary copy.
Is this an accurate interpretation? And if so, what C++ language feature or features are combining to allow {{c}} to create a temporary copy of c?
How objects and references are initialized is specified in [dcl.init]. Specifically [dcl.init]/16.1 says that initialization from braces instead of an expression is list-initialization.
How list-initialization is performed is specified in [dcl.init.list]/3. The first item in the chain that applies if the destination type is a reference is [dcl.init.list]/3.9, which says that if the braced-init-list from which we initialize has exactly one element of a type that is reference-related to the destination type, then the reference is initialized from that element instead. So Accept({c}); would initialize the reference in the function parameter by copy-initialization from c, causing it to bind directly to c.
You seem to expect this behavior to apply recursively if there are multiple layers of braces as well. However, in {{c}} the braced-init-list has exactly one element which itself is a braced-init-list {c} and braced-init-lists do not have a type (they are not expressions), so item [dcl.init.list]/3.9 on the list can't apply. The following item [dcl.init.list]/3.10 then applies to reference destination types and without further conditions specifies that a prvalue of the referenced type will be created and used to initialize the reference, meaning that a temporary object will be materialized that the function parameter will be bound to.
So nested braces will always initialize a reference with a temporary object, no matter what.
Specifically in your case it will end up as a temporary object initialized by a call to the implicitly-declared copy constructor of C which initializes the reference in the copy constructor's parameter with {c}, which in turn as described above means it binds directly to c, so that no further temporary will be created. It does not end up with aggregate initialization instead, because your class member is private and so the class is not an aggregate. If it was an aggregate (e.g. because you replace class with struct), then the initialization of the temporary would be ill-formed, because std::string can't be initialized from a C.
However, it seems that (at least in 2017) the C++ standard committee had some intentions to make your code ill-formed, see the note in CWG issue 2319. The suggestion at the end of the issue description would also make the initialization of the temporary object in your call Accept({{c}}) ill-formed for the non-aggregate case by disallowing the copy/move constructor to be used with nested braces.

When object is a argument of function, why does function use copy constructor?

I'm studying about copy constructors now. I learned that copy constructor is called when we make a object with already made object. And I heard that When we use object as a argument in function, copy constructor is called.
I want to know what happens inside function. How can function knows that function have to use copy constructor?
I think inside function, the passed argument is assigned to function parameter so that copy constructor is called.
I think inside function, the passed argument is assigned to function parameter
No. The arguments are essentially local variables of the called function, except they are created by the caller before the execution goes into the function. The function does not even know how they were constructed.
why does function use copy constructor?
So this assumption is wrong, the function does not use copy constructor on its arguments. The caller does (if argument is a variable and passed by value, so copy needs to be made).
How can function knows that function have to use copy constructor?
When passing the argument by value, the parameter is initialized by the passed argument. And from copy constructor's documentation:
The copy constructor is called whenever an object is initialized (by direct-initialization or copy-initialization) from another object of the same type (unless overload resolution selects a better match or the call is elided), which includes :
function argument passing: f(a);, where a is of type T and f is void f(T t);
So, since the passed argument is used to initialize the parameter(in case of pass by value), according to the above quoted statement, the copy constructor will be used.
Do note that in C++, assignment and initialization are different.
Additionally, note that move constructor can also be used instead of copy constructor in case the argument is an rvalue. From move constructor's documentation:
The move constructor is typically called when an object is initialized (by direct-initialization or copy-initialization) from rvalue (xvalue or prvalue) (until C++17)xvalue (since C++17) of the same type, including
function argument passing: f(std::move(a));, where a is of type T and f is void f(T t);
First of all, it's inaccurate to say that a copy constructor is called.
Let me give some examples:
void foo(string b);
...
{
string a = "asdf";
foo(a); // copy constructor is called to make string b
foo(std::move(a)); // move constructor is called to make string b
foo("asdfg"); // the string b is constructed inplace from "asdfg"
}
Basically, foo has the string as a local parameter and it needs to be constructed in some way. How exactly it is constructed is defined by the call.

Will this pair be moved?

Under the C++11 standard, is the following pair guaranteed to be moved into the function?
//objects available: key, value
//corresponding type available: pairtype
//function available: void foo(pairtype pair); copies the pair by default
foo({std::move(key),std::move(value)}); //pair moved?
or do I have to do the move myself?
foo(std::move(pairtype(std::move(key),std::move(value))); //needed?
Initializer lists are not expressions, so they do not have a type and they do not yield a value. This means that the following:
{std::move(key),std::move(value)}
Does not in itself create a pair. Initializer lists are just a syntactic construct used for initialization, and in this case the function parameter will be constructed by directly invoking the constructor of pairtype with std::move(key) and std::move(value) as arguments.
There is no creation of temporaries involved - the only thing to be aware of is that explicit constructors will not be considered when performing list-initialization (for instance, this would not work with an instance of std::tuple<>).
Which means that the invocation of foo we just discussed, i.e.:
foo({std::move(key),std::move(value)}
Is technically different from this invocation:
foo(std::move(pairtype(std::move(key),std::move(value)))
Here, you are intentionally creating a temporary and moving it into the function parameter (the compiler may then elide this move per 12.8/31, but this is another story).
Notice, that the call to std::move() here is superfluous, since temporaries are rvalues. The function parameter will be move-constructed from the temporary object anyway. You can therefore write:
foo(pairtype(std::move(key),std::move(value)))
Notice, that pairtype will be an instance of the std::pair<> class template, which means you will have to specify template arguments manually. To avoid this, you can use std::make_pair():
foo(std::make_pair(std::move(key),std::move(value)))

initializing a non-copyable member (or other object) in-place from a factory function

A class must have a valid copy or move constructor for any of this syntax to be legal:
C x = factory();
C y( factory() );
C z{ factory() };
In C++03 it was fairly common to rely on copy elision to prevent the compiler from touching the copy constructor. Every class has a valid copy constructor signature regardless of whether a definition exists.
In C++11 a non-copyable type should define C( C const & ) = delete;, rendering any reference to the function invalid regardless of use (same for non-moveable). (C++11 §8.4.3/2). GCC, for one, will complain when trying to return such an object by value. Copy elision ceases to help.
Fortunately, we also have new syntax to express intent instead of relying on a loophole. The factory function can return a braced-init-list to construct the result temporary in-place:
C factory() {
return { arg1, 2, "arg3" }; // calls C::C( whatever ), no copy
}
Edit: If there's any doubt, this return statement is parsed as follows:
6.6.3/2: "A return statement with a braced-init-list initializes the object or reference to be returned from the function by copy-list-initialization (8.5.4) from the specified initializer list."
8.5.4/1: "list-initialization in a copy-initialization context is called copy-list-initialization." ¶3: "if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (13.3, 13.3.1.7)."
Do not be misled by the name copy-list-initialization. 8.5:
13: The form of initialization (using parentheses or =) is generally insignificant, but does matter when the
initializer or the entity being initialized has a class type; see below. If the entity being initialized does not
have class type, the expression-list in a parenthesized initializer shall be a single expression.
14: The initialization that occurs in the form
T x = a;
as well as in argument passing, function return, throwing an exception (15.1), handling an exception (15.3), and aggregate member initialization (8.5.1) is called copy-initialization.
Both copy-initialization and its alternative, direct-initialization, always defer to list-initialization when the initializer is a braced-init-list. There is no semantic effect in adding the =, which is one reason list-initialization is informally called uniform initialization.
There are differences: direct-initialization may invoke an explicit constructor, unlike copy-initialization. Copy-initialization initializes a temporary and copies it to initialize the object, when converting.
The specification of copy-list-initialization for return { list } statements merely specifies the exact equivalent syntax to be temp T = { list };, where = denotes copy-initialization. It does not immediately imply that a copy constructor is invoked.
-- End edit.
The function result can then be received into an rvalue reference to prevent copying the temporary to a local:
C && x = factory(); // applies to other initialization syntax
The question is, how to initialize a nonstatic member from a factory function returning non-copyable, non-moveable type? The reference trick doesn't work because a reference member doesn't extend the lifetime of a temporary.
Note, I'm not considering aggregate-initialization. This is about defining a constructor.
On your main question:
The question is, how to initialize a nonstatic member from a factory function returning non-copyable, non-moveable type?
You don't.
Your problem is that you are trying to conflate two things: how the return value is generated and how the return value is used at the call site. These two things don't connect to each other. Remember: the definition of a function cannot affect how it is used (in terms of language), since that definition is not necessarily available to the compiler. Therefore, C++ does not allow the way the return value was generated to affect anything (outside of elision, which is an optimization, not a language requirement).
To put it another way, this:
C c = {...};
Is different from this:
C c = [&]() -> C {return {...};}()
You have a function which returns a type by value. It is returning a prvalue expression of type C. If you want to store this value, thus giving it a name, you have exactly two options:
Store it as a const& or &&. This will extend the lifetime of the temporary to the lifetime of the control block. You can't do that with member variables; it can only be done with automatic variables in functions.
Copy/move it into a value. You can do this with a member variable, but it obviously requires the type to be copyable or moveable.
These are the only options C++ makes available to you if you want to store a prvalue expression. So you can either make the type moveable or return a freshly allocated pointer to memory and store that instead of a value.
This limitation is a big part of the reason why moving was created in the first place: to be able to pass things by value and avoid expensive copies. The language couldn't be changed to force elision of return values. So instead, they reduced the cost in many cases.
Issues like this were among the prime motivations for the change in C++17 to allow these initializations (and exclude the copies from the language, not merely as an optimization).

what happens when i only call a constructor?

This may sound naive. I want to know what happens when i explicitly call a constructor like this:
class A{
/*...*/
public:
A(){}
};
int main(){
A();
return 0;
}
Is a useless object created which remains in the memory until the scope of main() ends?
You create an object that lasts until the end of the statement.
Its considered a nameless temporary which gets destroyed after the end of the full expression. In this case, the point right after the semicolon. To prove this, create a destructor with a print statement.
when i explicitly call a constructor like this
You are not calling a constructor here; but creating a temporary object which gets destructed immediately. Constructor can be called explicitly with an object of that type (which is not advisable).
Is a useless object created which remains in the memory until the
scope of main() ends?
It doesn't have scope till the function ends, but till the ; ends.
Strictly speaking you can never make a direct call to a constructor in C++. A constructor is called by the implementation when you cause an object of class type to be instantiated.
The statement A(); is an expression statement and the expression is a degenerate form of an explicit type conversion (functional notation). A refers to the type, strictly speaking constructors don't have names.
From the standard (5.2.3 [expr.type.conv] / 2:
The expression T(), where T is a simple-type-specifier for a non-array complete object type or the (possibly cv-qualified) void type, creates an rvalue of the specified type, which is value-initialized [...].
Because your class type has a user-declared default constructor the value-initialization of this temporary will use this constructor. (see 8.5 [dcl.init]/5)
Okay, I re-visited temporary and found that in the above example, it's actually a part of expression that is initializing an object. So yes, the scope ends at ;
Here:
When a temporary object is created to initialize a reference variable, the name of the temporary object has the same scope as that of the reference variable. When a temporary object is created during the evaluation of a full-expression (an expression that is not a subexpression of another expression), it is destroyed as the last step in its evaluation that lexically contains the point where it was created.