Foo f1 = Foo(); // (1) Ok
Foo f2 = Foo; // (2) Compiler error
Foo *p1 = new Foo(); // (3) Ok
Foo *p2 = new Foo; // (4) Ok. Why??
I was wondering why there exists two ways to initialize pointers. It looks a little inconsistent. Is there some logical reason, and if so, what? Or, maybe it's some kind of legacy? And if so, What is the origin of such notation?
It's a bit... complicated, to say the least.
When dealing with objects, both notations are equivalent. When dealing with primitive types (such as int), (3) will initialize (zero fill) the value, while (4) will not (the value will be left undefined).
For automatically allocated objects, this:
Foo f1;
Declares and initializes a Foo object using the default constructor. This:
Foo f2 = Foo();
Declares and initializes a Foo object using the copy constructor, essentially copying the value of a temporary object (the Foo()), which is built with the default constructor.
I give you that it seems illogical, but if you think about the possible meanings, it makes a lot of sense.
Without knowing what Foo might be, neither a human nor the compiler (here, the human perspective is more important) would be able to determine if Foo f2 = Foo; is a) creating a new temporary Foo object and copy constructing another one with it or b) assigning the value of a variable Foo to the copy constructed object (f2). It may seem obvious for us because our convention tells us that Foo must be a type as it is capitalised, but in general it is not that simple (again: this mainly applies to a human reader that does not necessarily have the whole source code memorised).
The difference between (2) and (4) is that for the latter, only one interpretation is admissible, because new var (where var is a variable) is not a legal expression.
The equivalent of 4 for scope-based resources is actually just
Foo f;
The legacy reason for the differences is essentially that in C, primitive types, such as int, were not default-initialized to something useful. C++ inherited this behaviour for performance reasons- at the time. Of course, now, it's a trivial amount of processor time to expend. In C++, they introduced a new syntax by which it would always be initialized- the brackets.
int i = int();
i is always guaranteed to be 0.
int i;
The value of i is undefined.
This is the exact same as for the pointer variety, just with some new:
int* i = new int(); // guaranteed 0
int* i = new int; // undefined
Related
Foo(Foo&& other) {
this->bar = other.bar;
other.bar = nullptr;
}
Foo(Foo* other) {
this->bar = other->bar;
other->bar = nullptr;
}
The above two seem to be just doing the same. So why is it recommended to use move constructor? What advantages does it provide?
The reasons for using a proper move constructor are many:
Convention. Consider the following code:
Foo foo;
Foo bar(std::move(foo));
If you see that code, it is abundantly clear what you're trying to do: you're moving foo into bar. By contrast:
Foo foo;
Foo bar(&foo);
What does this mean? Is it storing a pointer to another Foo? Is Foo some sort of linked list node type? You'd have to look it up in the documentation for Foo's pointer-based constructor.
You can't get a pointer to prvalues. Foo bar(Foo{}) would (pre-C++17) create a prvalue temporary and then move from it into bar (the move could be elided pre-C++17). But you can't do this: Foo bar(&Foo{}).
You get automatic movement from things where it makes sense. C++17's generalized elision makes many of these automatic moves go away, but there are some that remain:
Foo function()
{
Foo foo;
//Do stuff
return foo;
}
This will move from foo without having to call std::move. The reason is that foo is a local variable that is about to be destroyed. Returning it in this way means that it's perfectly reasonable to move from it into the return value.
Your way would require explicitly writing return &foo. And that makes things rather difficult with auto return type deduction. Such a function would deduce a Foo*, which means you just returned a dangling pointer. Whereas if you do return foo;, it deduces a Foo prvalue, with an automatic move (that may be elided).
No need for nullptr checks. If you take a Foo*, it's possible that someone would pass a null pointer. Whereas with a reference, it's far more unlikely (and they'll have already invoked UB).
If we wanted move support with existing language constructs, we'd have just used a non-const reference to mean "move", not a pointer. By giving it its own syntax, make it clear when we're moving something and when we aren't.
I have a conceptual question to help me as a fairly novice C++ programmer. What is the advantage, if any, of C++ allowing mixing, or "co-mingling", of declarations and executables? As I beginner, all I can think of is that this is not a feature available in C. And obviously, you can combine some lines of code by not having to declare variables at the beginning of a particular scope, but rather you could declare in the instruction itself. Wish I had more to tell you all but I really do not know. Maybe a push in the right direction would help! Thanks!
This is REQUIRED in cases where you need to take a reference from the result of a function.
SomeType& func();
....
...
... Some code that is needed to make `func` work, for example
... opening a file or initializing some global variables.
SomeType& x = func();
...
It does not work to declare x at the start of a block, as C pre-C99 requires in this case, since references can not be declared without initializing the referant into the reference.
The other point is that you can avoid "default constructing" and then initializing a variable, which is a similar:
SomeType x(func());
would avoid calling the default constructor of SomeType.
But generally, the compiler will take care of removing unnecessary constructors, so it's much less of an issue than the first case.
The main advantage is making the code easier to read - instead of having a statement like myVar = doSomething(p1, p2, p3); and having to scroll all the way up to the beginning of the scope to recall what myVar was, you could have a single, clearer, one liner MyClass myVar = doSomething(p1, p2, p3);.
There are at least three of advantages/benifits here.
no uninitialized/default initialized values and better scoping
int a = -1;
int b;
... // Use of `a` is meaningless here, use of `b` is also dangerous
a = f(); b = g();
vs.
... // Uses of `a` and `b` are compiler errors
int a = f(), b = g();
more effective object creation
Object o; // default ctor
...
o = Object(1, 2, 'a'); // ctor + move-assignement operator
vs.
...
Object o(1, 2, 'a'); // ctor
RAII
mtx.lock();
...
mtx.unlock();
vs.
{
std::lock_guard<mutex> guard(mtx); // implicit mtx.lock()
...
} // automatically generated mtx.unlock();
class C{
//methods and properties
}
void C::some_method(C* b){
delete this;
this = b;
}
This gives me follwing error when compiling:
error: lvalue required as left operand of assignment
My intention:
Say there are objects a and b of class C. The contents of the class C can be very huge and field by field copying can be very costly. I want all the contents of 'a' to be replaced by 'b' in an economical way.
Will default copy constructor do the intended task?
I found something called 'move constructor'
http://akrzemi1.wordpress.com/2011/08/11/move-constructor/
Perhaps, it might get the effect that I want.
The this-pointer is an implicit pointer to the object in whose context you are working, you cannot reassign it.
According to Stroustrup's bible (The C++ Programming Language, 3rd edition I have) this is expressed as
C * const this
meaning you have a constant pointer to your class C, so the compiler will complain if you try to change it.
EDIT:
As I was corrected, the above mentioned expression does not describe this fully correctly, for this is actually an rvalue.
You cannot change what this points to. I would also not know why you'd want to do this.
To quote the standard:
In the body of a non-static (9.3) member function, the keyword
this is a prvalue expression whose value is the address of the
object for which the function is called.
A "prvalue" is a pure rvalue, something like 42 or 3.14159.
In the same way you can't do something like 42 = x, you can't
assign to this; in both cases (at least conceptually), there
is no object whose value can change.
And I'm really curious as to what you expect to happen if
I write something like:
int
main()
{
C c1;
C c2
c1.some_method( &c2 );
}
Do you expect the address of c1 to somehow miraculously
change, and for c1 and c2 to be aliases to the same object?
(And c1.some_method( NULL ) is even more intreguing.)
You can't assign a different value to this as it point to the object itself, and this haven't any sense.
You could instantiate a new object and use its implicit this pointer instead.
Moreover, if you try to make a copy of object, you can overwrite operator=
class Foo
{
public:
[...]
Foo& operator=(const Foo& foo);
}
int main()
{
Foo foo;
foobar = foo; //invoke operator= overwrited method
}
The error says "You can't assign b to this". As far as I know, this is something you can't change, because it's not an actual pointer, but a self-reference.
Just use the usual approach instead of black magic and UB:
C* c1 = new C();
C* c2 = new C();
// do some work perhaps ...
delete c1;
c1 = c2;
Now c1 is an alias to c2 as you wanted. Be careful though when cleaning up memory so you don't end up deleting an object twice. You might perhaps consider smart pointers...
#include <iostream>
class Bar
{
protected:
public:
int & x;
Bar(int & new_x)
:x(new_x)
{}
Bar & operator = (const Bar toCopy)
{
x = toCopy.x;
return *this;
}
};
int main()
{
int x1(1);
int x2(2);
Bar bar = Bar(x1);
std::cout << bar.x << std::endl;
bar = Bar(x2);
std::cout << bar.x << std::endl;
bar.x = 5;
std::cout << bar.x << std::endl;
std::cout << x1 << std::endl;
std::cout << x2 << std::endl;
}
The output is:
1
2
5
5
2
What I am trying to do is copy x and save it within the object bar.
The output suggests to me that the assignment operator has not done its magic, both in terms of copying and taking the value of the new object. I have followed this link.
Changing x into a value rather than a reference is not possible, as in the real program x is an abstract class.
Please if possible abstain from using heap assignment.
EDIT:
1. I realized that I have just butchered the C++ language. I would like to apologize to all "C++ian" speaking computers. My motivation was to assign a member abstract variable on the stack. As far as I understand, it cannot be done on the stack, because the size of the derived class is not known at compile time.
2. OK... I am a total n00b...(no sh*t, Sherlock!). "Effective C++ programming" #rhalbersma is a must have. It contains essentials, yet you wont find them anywhere (copy constructions, copy initializer),.. in one place anyway.
References can be confusing. So can const pointers. I'll try to clear things up by talking about both of them at the same time. What can I say, I'm an optimist.
First, const pointers.
We'll start with a class called Foo. We can have a pointer to this class -- a Foo*. We can have a pointer to a const instance of this class -- a Foo const*. And we can have a const pointer to a non-const instance of this class -- a Foo*const.
A Foo const* is a pointer you can change to data you cannot change.
A Foo*const is a pointer you cannot change to data you can change.
I'll assume you got that. I am, after all, an optimist. Next, lets look at references.
While it is true that references are aliases, sometimes it helps to think about them in a world where things have concrete implementations in terms of other types.
A Foo& is analogous to a Foo*const -- a non-changeable "pointer" to an instance of Foo you can change. So the Foo you are talking about is always the same one, but you can change its state.
Now, it is a bit more than that. There is some syntactic sugar. When you create a reference to another variable, it does the & automatically -- so when you do a Foo& f = a;, this is analogous to Foo*const f = &a;.
Second, when you use ., it does the same as -> in the pointer case. (And similarly for (most?) other operators)
Third, when you do assignment, it clearly cannot change the pointer's value -- because it is const -- but instead it changes the value of the thing pointed to. So Foo& f = a; a = b; does the equivalent of Foo*const f = &a; *f = b;.
It assigns the thing pointed to, rather than the pointer, when you use operator=. But when you initialize it, it doesn't use operator=, even if you have a = token.
Initialization is not the same as assignment in general, and the semantics of what happens with a & reference and a * pointer in initialization and assignment are very different.
Foo& f = a; f = b; does two completely different things. Initialization of a reference initializes the "const pointer" portion -- assignment to a reference modifies the thing pointed to.
My personal name for how initialization and assignment mean different things with references is "reference semantics", as opposed to "pointer semantics" where both initialization and assignment change what thing is being pointed to. In "reference semantics", initialization picks what thing is being pointed to, and assignment changes the state of the thing that is pointed to.
This is highly confusing, and I hope I helped make it confusing in a different way.
Bar bar = Bar(x1); is not assignment, but copy-initialization. It calls the copy constructor, not the copy assignment operator.
The problem though is that you don't understand reference - the member Bar::x is just an alias for another variable. Assigning something to it will also modify the original one.
The x inside bar is the same variable as the one called "x1" in main.
That's what references do - they take a variable and give it another name that you can use to refer to it.
Whatever you do to that variable under this new name is the same as doing it under any other name.
First, after
Bar bar = Bar(x1);
(which is copy initialization, not assignment)
"bar.x" refers to the same variable as the "x" inside the anonymous object on the right hand side, which in turn is a different name for "x1" in main.
After this, the name "bar.x" refers to the same variable as the name "x1".
The line
bar = Bar(x2);
assigns the value (i.e., 2) of the anonymous object's x, which is the same variable as x2, to the variable that is called "x" inside bar, but whose name is "x1" in main.
The line
bar.x = 5;
then assigns the value 5 to the variable whose name is "bar.x" which, again, is the same variable as "x1" in main.
You cannot make it refer to a different variable.
If you want something that can refer to different variables, you must use a pointer.
I'm relatively new to C++ and I'm wondering if structs are copied in the following case:
struct foo {
int i;
std::vector<int> bar;
}
class Foobar {
foo m_foo;
void store(foo& f) {
this->m_foo = f;
}
}
void main() {
Foobar foobar;
{
foo f;
f.i = 1;
f.bar.insert(2);
foobar.store(f);
}
// will a copy of f still exist in foobar.m_foo, or am I storing a NULL-Pointer at this point?
}
The reason why I am asking this is that I am originally a .NET developer and in .NET structures will be copied if you pass them to a function (and classes are not).
I'm pretty sure it would be copied if store was not declared to take f by reference, but I cannot change this code.
Edit: Updated the code, because I didn't know that the vector.insert would affect my question. In my case I store the struct as a member in a class, not a vector.
So my question really was: will f be copied at this->m_foo = f;?
Short answer: Yes.
Long answer: You'd have to get a pointer to a stack allocated struct and then let that struct go out of scope in order to end up with a dangling reference in your vector... but even then, you wouldn't have stored a NULL. C and C++ pointers are simple things, and will continue to point at a memory location long after that memory location has become invalid, if your code doesn't overwrite them.
It might also be worth noting that std::vector has a decent set of copy and move functions associated with it that will be called implicitly in this case, so the bar vector inside the struct will also be copied along with the simple integer i. Standard library classes tend to be quite well written, but code by other folk has no such guarantee!
Now, as regards your edit:
class Foobar {
foo m_foo;
void store(foo& f) {
this->m_foo = f;
}
}
You will still not have any problems with the foo instance stored in m_foo. This is because this->m_foo = f invokes a copying operation, as m_foo is not a variable of a reference or pointer type. If you had this instead: foo& m_foo then you would run into difficulties because instead of copying a foo instance you are instead copying a reference to a foo instance, and when that instance goes out of scope, the reference is no longer valid.
Yes, the struct will be copied, in the following function:
foos.insert(f);
As a copy is made, you won't be storing a null pointer / null reference.
However, like you've said, it won't be copied when you call store(f); as the function accepts the argument as a reference.
Your edit will still make a copy of Foo. You are assigning one instance of a variable to another instance of a variable. What you aren't doing is assigning one pointer (reference in C#) to another. You could probably do with doing some reading around C++ object instances, pointers, and references.
A copy of f is made during foos.insert(f)
void store(foo& f) {
foos.insert(f);
}
void main() {
{
foo f;
f.i = 1;
f.bar.insert(2);
store(f);
}
// at this place, local variable `f` runs out of scope, it's destroyed and cleaned up
// foos is holding the copy of `f`
}