I read a book S. Lippman "inside c++ object model", is there such code
class Foo { public: int val; Foo *pnext; };
void foo_bar()
{
// Oops: program needs bar's members zeroed out
Foo bar;
Foo* baz = new Foo(); // this line i added myself
if ( bar.val || bar.pnext )
// ... do something
// ...
}
and it says that
"A default constructor is not synthesized for this code fragment.
Global objects are guaranteed to have their associated memory "zeroed out" at program start-up. Local objects
allocated on the program stack and heap objects allocated on the free-store do not have their associated memory
zeroed out; rather, the memory retains the arbitrary bit pattern of its previous use."
In this code the baz object was created on the heap, and according to what has been said above this object is not global and it will not be called the default constructor. I understand correctly ?
The parentheses in new Foo() specify value initialisation; this basically means that each member is zero-initialised. If instead you said new Foo, then the members would be left uninitialised, as they are for your automatic variable.
Unfortunately, to value-initialise the automatic variable, you can't write Foo bar(), since that declares a function. You'll need
Foo bar{}; // C++11
Foo bar = Foo(); // Historical C++
When you do this:
Foo* baz = new Foo();
you are dynamically allocating a Foo instance and value-initializing it. For PODs, this means the members get zero-initialized. If you had said this (assuming non-global context):
Foo* baz = new Foo;
then the Foo instance would be default initialized, which would mean no initialization of its members is performed, since they are PODs.
This also applies to automatic storage instances:
Foo f0; // default initializaiton: members not zeroed out.
Foo f1 = Foo(); // value initialization: members zeroed out.
Foo f2{}; // C++11 value initialization: members zeroed out.
Foo f3(); // Ooops! Function declaration. Something completely different.
If a class have no default constructor (and no other constructor), the compiler will create one for you. It has to, or you would not be able to create instances of the class. However, the generated default constructor will not do anything.
What adding the empty set of parentheses in new Foo() does, is to value initialize the allocated object, which means the members gets initialized to their "default" values, which is zero for integer and floating point values, and nullptr for pointers.
Related
I have a function that returns an object via a pointer argument. However the object has a private default constructor, so how can I create a variable to pass the address in?
class Foo {
Foo(/*some parameters*/);
private:
Foo();
};
void bar( Foo* foo ) {
*foo = Foo(/*some arguments*/);
}
Foo f; //doesn't compile because default constructor is private
bar( &f );
The code is simplified, I can't really change Foo or bar
Simply use the public, non-default constructor to create the first version of the Foo instance, that will be re-assigned in bar:
Foo f(/*some arguments*/);
bar(&f);
It probably won't matter which argument values you pass, unless the move assignment operator does something special with the old values.
Yes, it seems pointless, but Foo has been designed so that bar is really inconvenient to use (or the other way round).
So there is no way to say just create some space in memory that will fit a Foo, I'll fill it in later?
Not using bar. bar does an assignment, and an assignment requires the left hand side to be an existing object, that is in a valid state.
So why isn't it possible in C++ to create a variable without creating an object?
Why is it in C++ variable and object are so tightly related?
Because that is the way C++ has been specified. A variable is a name for an object. It is not a name for something that might be an object or might be not-an-object. And it's a good decision too. Thanks to this design, you can always rest assured, that the object named by a variable does always exist sans a bug in your program. (Reference variables are different, since they aren't an object themselves).
The issue with Foo and bar isn't a limitation of the language. The issue is bad design of Foo and/or bar.
This doesn't answer the question, because it relies on changing bar, but to answer this comment:
So there is no way to say just create some space in memory that will fit a Foo, I'll fill it in later?
For objects of non-trivial types (like the Foo in your example) the only way to do that is construct a new object at that address, not assign to an existing object. You can do that with a placement new-expression:
void bar( Foo* foo ) {
new (foo) Foo(/*some arguments*/);
}
Now instead of the address of an existing object, the argument to the function needs to be a chunk of uninitialized memory which is suitably-aligned for a Foo object, which you can do with the aligned_storage type:
std::aligned_storage<sizeof(Foo), alignof(Foo)>::type storage;
Foo* addr = reinterpret_cast<Foo*>(&storage);
bar( addr );
However, because you've manually started the lifetime of a Foo at that location, it's also your responsibility to manually end its lifetime, by explicitly invoking the destructor when you're finished with it:
addr->~Foo();
This is obviously more error-prone than relying on the compiler to construct and destroy your object automatically.
I think the person who had written the code for class Foo did not want anyone to create objects of class Foo using default c'tor. Instead he/she wanted to create the objects of class Foo using method bar();
So try this:
class Foo {
Foo(/*some parameters*/);
private:
Foo();
};
void bar( Foo** foo ) {
//*foo = Foo(/*some arguments*/);
*foo = new Foo(/*some arguments*/);
}
Foo *f = NULL; //doesn't compile because default constructor is private
bar( &f );
Note: You need to create a pointer to class Foo i.e *f and pass the address of this pointer. Inside method bar() an object of class Foo will get created and this object's address will be assigned to the pointer f.
it is stated on this website: http://www.tutorialspoint.com/cplusplus/cpp_variable_scope.htm
Variables that are declared inside a function or block are local
variables. They can be used only by statements that are inside that
function or block of code. Local variables are not known to functions
outside their own.
Then, in the following example;
class foo {
/*....*/
};
foo bar(){
foo f;
return f;
}
void main(){
foo fooReturn = bar();
}
how come when bar() returns, fooReturn contains a valid object? is:
foo f similar to foo *f = new foo(); are both objects on the heap?
thanks
daniel
No, foo f; is very different from foo * f = new foo();, since the former foo is built on the stack, its destructor is automatically called when it goes out of scope, etc.
Instead, the latter foo is built on the heap, requires manual destruction calling delete, etc.
But, in your sample code, the returned foo f is copied or moved (if foo provides move semantics, e.g. move constructor), out of the function bar(). So you have a valid object returned to the caller.
Note
The be more precise, there is an optimization that the C++ compiler may apply, i.e. the RVO (Return Value Optimization), that could avoid the copy or move of the returned foo.
how come when bar() returns, fooReturn contains a valid object?
Because the value of the return expression (f) is used to initialise fooReturn before it's destroyed. As long as the type has correct copy/move semantics, or the copy/move is elided, the resulting object will be valid.
is: foo f similar to foo *f = new foo(); are both objects on the heap?
No, the first is an automatic variable, stored in the function's stack frame and destroyed when it goes out of scope. The second is a dynamic object, stored on the heap, and not destroyed without an explicit delete.
When you return a local object from a function, a copy is created (with a copy costructor). In your example, fooReturn contains a copy of the f object (local to bar). After the f is copied, it is freed.
I would like to recycle memory for an object rather than deallocating and reconstructing it. Is the following usage of "placement new" safe, assuming that Foo in practice does not contain pointers (but might contain functions)?
Also, is the final delete call safe, and will it correctly call the destructor on the second "new" object, and correctly free the memory afterwards?
#include <new>
struct Foo {
int hello;
int world;
};
int main() {
Foo* foo = new Foo;
// Do something with foo
// Done with foo, writing a new version of foo on top of the old one.
new(foo) Foo();
delete(foo);
}
The simple example above compiles and runs without errors, but I cannot tell by running it whether it might blow up for some reason in a more complex environment.
It's safe because the object you're overwriting has a trivial destructor. From n3337, chapter 3.8 (Object lifetime):
4 A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly
calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type
with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage
which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a
delete-expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and
any program that depends on the side effects produced by the destructor has undefined behavior.
The delete call is safe, too. You're calling it on a pointer that you got from new and there's a live object at that place.
And as you hinted in the question, it could invoke undefined behaviour if the destructor is non-trivial and has side effects - you need to call it explicitly in that case. Whether or not the class contains pointers is not directly important - reusing the storage is safe even in that case, but of course, you could introduce memory leaks and other bugs that way.
No, it is not dangerous to reuse memory of an object, provided that you are doing it correctly. Moreover, you do not have to restrict yourself to objects that have no pointers: by calling the destructor explicitly you can prepare the object for reuse, like this:
Foo* foo = new Foo;
// Do something with foo
// Done with foo, writing a new version of foo on top of the old one.
foo->~Foo(); // Call the destructor explicitly to clean up the resources of a Foo
new(foo) Foo(); // Place new data into the previously allocated memory
delete(foo); // We are deleting a fully initialized object, so it is OK
There have been two answers already, but they give, I fear, an incomplete picture.
You may reuse the storage of an object, providing that you respect a few conditions:
You need not use a dynamically allocated object, any object is fine.
You should properly destroy the previous object, by calling its destructor (explicitly); failure to do so leads to undefined behavior if the destructor has side-effects (see §3.8/4)
The object that you place should have the same dynamic type as the previous object (see §3.8/7)
Let us review them, starting with any object is fine:
struct Foo {
int hello;
int world;
};
void automatically_allocated() {
Foo foo;
foo.~Foo();
new (&foo) Foo{};
}
void dynamically_allocated() {
std::unique_ptr<Foo> foo(new Foo{});
foo->~Foo();
new (&*foo) Foo{};
}
Let use continue with destroy the previous object:
struct Bar {
int hello;
std::string world;
};
void UNDEFINED_BEHAVIOR() {
Bar bar;
new (&bar) Bar{}; // most likely scenario: leaks memory owned by bar.world
}
And finally with same dynamic type:
struct Base { virtual ~Base() {} };
struct Derived: Base { std::string world; };
struct Other: Base { int hello; }
void UNDEFINED_BEHAVIOR() {
Derived derived;
Base& b = derived;
b.~Base(); // fine
new (&b) Other{};
// Most likely here, calls "derived.~Derived()" on an object of type Other...
}
I wrote the following code snippet:
void foo()
{
struct _bar_
{
int a;
} bar;
cout << "Value of a is " << bar.a;
}
and compiled it with g++ 4.2.1 (Mac). The output is "Value of a is 0".
Is it true to say that data members of a struct in c++ are always initialized by default (compared to c)? Or is the observed result just coincidence?
I can imagine that structs in c++ have a default constructor (since a struct and a class is almost the same in c++), which would explain why the data member a of bar is initialized to zero.
The simple answer is yes.
It has a default constructor.
Note: struct and class are identical (apart from the default state of the accesses specifiers).
But whether it initializes the members will depends on how the actual object is declared. In your example no the member is not initialized and a has indeterminate value.
void func()
{
_bar_ a; // Members are NOT initialized.
_bar_ b = _bar_(); // Members are zero-initialized
// From C++14
_bar_ c{}; // New Brace initializer (Members are zero-initialized)
_bar_* aP = new _bar_; // Members are NOT initialized.
_bar_* bP = new _bar_(); // Members are zero-initialized
// From C++14
_bar_ cP = new _bar_{}; // New Brace initializer (Members are zero-initialized)
}
// static storage duration objects
// i.e. objects at the global scope.
_bar_ c; // Members are zero-initialized.
The exact details are explained in the standard at 8.5 Initializers [dcl.init] paragraphs 4-10. But the following is a simplistic summary for this situation.
A structure without a user defined constructor has a compiler generated constructor. But what it does depends on how it is used and it will either default initialize its members (which for POD types is usually nothing) or it may zero initialize its members (which for POD usually means set its members to zero).
PS. Don't use a _ as the first character in a type name. You will bump into problems.
Is it true to say that data members of a struct in c++ are always initialized by default (compared to c)? Or is the observed result just coincidence?
It is a coincidence.
Your code invokes Undefined Behavior; unless you explicitly set the members to 0 they can be anything.
Not an answer, but you might take it to be... if you want to try it:
void foo() {
struct test {
int value;
} x;
std::cout << x.value << std::endl;
x.value = 1000;
}
int main() {
foo();
foo();
}
In your example, the memory already had the 0 value before the variable was created, so you can call it a lucky coincidence (in fact, some OS will zero out all memory before starting a process, which means that 0 is quite a likely value to find in a small short program...), the previous code will call the function twice, and the memory from the first call will be reused in the second one, chances are that the second time around it will print 1000. Note however that the value is still undefined, and that this test might or not show the expected result (i.e. there are many things that the compiler can do and would generate a different result...)
Member variables of a struct are not initialized by default. Just like a class (because a struct is exactly the same thing as a class, only in struct the members are public by default).
Do not rely on this functionality it is non-standard
just add
foo() : a() {}
I can't remember the exact state of gcc 4.2 (i think it is too old) but if you were using C++11 you can do the following
foo()=default;
For a programming assignment, we are given a template class with two members declared not as pointers, but actual objects:
Foo member;
In the constructor, I tried member = *(new Foo()); initially, but learned that, at least sometimes, it was copying the new Foo object, and therefore causing memory leaks.
I finally discovered member = Foo(), and then looked up what the difference was. I learned that member will be allocated on the stack instead of the heap, and that it will be deleted once it is out of scope. How does this work for objects, though?
Is member only deleted when the parent / class object is deleted?
I also have another question about member = *(new Foo());. I was initializing two member variables of the same type:
// Members
Foo member1;
Foo member2;
// Constructor {
member1 = *(new Foo());
member2 = *(new Foo());
}
For some reason it seemed member1 was not being copied and it retained the same address as the initial Foo (i.e. there was no memory leak when it was deleted). member2 however, would be copied and had a different address, and memory was leaked. Is there an explanation for this?
Your analysis is incorrect. Both of these are memory leaks. What you are doing is allocating a new copy of the object, assigning the value to the member, and then discarding the pointer to the allocated memory without freeing that memory. It is a memory leak in both cases.
Now, consider the following code:
class MemberType {
public:
MemberType() { std::cout << "Default constructor" << std::endl; }
MemberType(int) { std::cout << "Int constructor" << std::endl; }
};
class Example1 {
public:
Example1() {}
private:
MemberType member_;
};
class Example2 {
public:
Example2() : member_(5) {}
private:
MemberType member_;
};
int main(int argc, char** argv) {
Example1 example1;
Example2 example2;
return 0;
}
This code will print both different types of constructors. Note that it did not take any initialization code at all for the member to be initialized in the default manner. Hence your new statement (or even an assignment without new) would be unnecessary in the default initialization case. When initializing members using a constructor other than the default constructor, the proper way to do this is with an initializer list. (The initializer list is what is happening with ": member_(5)" in the example.
Please see the C++ FAQ on constructors for more information about constructing objects in C++.
member = *(new Foo());
new Foo() dynamically allocates a Foo object and returns a pointer to that object. The * dereferences that pointer, giving you the Foo object. This object is then assigned to member, which involves calling the Foo copy assignment operator. By default, this operator assigns the values of each of the members of the right-hand side (the *(new Foo())) object into the left-hand side object (the member).
The problem is this: new Foo() dynamically allocates a Foo object and that object is not destroyed until you delete the pointer returned from the new. You don't save that pointer anywhere, so you've leaked the dynamically allocated object.
This is not the correct way to initialize an object.
member = Foo();
This creates a temporary, initialized Foo object and this object is assigned to member. At the end of this statement (at the ;, effectively), the temporary object is destroyed. member is not destroyed, and the contents of the temporary Foo object were copied into member, so this is exactly what you want to do.
Note that the preferred way to initialize member variables is using the initializer list:
struct C {
Foo member1, member2;
C() : member1(), member2() { }
};