The relevant part of my code is as follows:
In foo.h:
namespace foo_ns {
class Foo
{
static Class1 object1;
};
}
In foo.cpp
#include <foo.h>
namespace foo_ns {
Class1 Foo::object1(/*another object. Need to call copy constructor*/)
}
Here, "another object" is defined in main(). Furthermore, Class1 is part of a large library and has no zero argument constructors, so simply removing the parenthesis gives a no matching function call error during compilation. From what I understand, static initialization MUST be performed outside of any function.
So ithere any workaround for this?
Of course, if Class1 has methods that you can use later then an easy solution would be:
Class1 Foo::object1(some_rubbish);
// in main
object1 = Class1(the_real_initializer);
If Class1 does not have a working assignment operator, but it can safely be destroyed and re-created, you can write in main:
object1.~Class1();
new(&object1) Class1(the_real_initializer);
although if this constructor throws then you have to abort the program.
If it is not possible to destroy a Class1 correctly before the end of the program then you will have to defer its initialization, e.g.:
static std::unique_ptr<Class1> p_object1;
and then in main, when you are ready,
p_object1.reset( new Class1(bla bla bla) );
This way you will have to change any other code that accesses object1. to use p_object1-> instead.
Related
I got a small problem which i don't understand for now and can't find explanation for it. I read about how to use std::unique_ptr in PIMPL idiom and it works but.. not in one weird situation, which of course occured to me now.
The simplest - i will show a simplified code example which reproduce a problem (Compiling with VS2017 Community).
header.h ##
Forward declaration of Forward class, and template class TestForward which has virtual function returning unique_ptr.
class Forward;
using TestUniquePtr = std::unique_ptr<Forward>;
TestUniquePtr make_ptr();
template<int a>
class TestForward {
public:
virtual TestUniquePtr foo();
};
template<int a>
TestUniquePtr TestForward<a>::foo() {
return make_ptr();
}
forward.h
#include "header.h"
#include <iostream>
class Forward {
public:
~Forward() {
std::cout << "HAAA" << std::endl;
}
};
forward.cpp
#include "forward.h"
TestUniquePtr make_ptr() {
return TestUniquePtr{ new Forward };
}
main.cpp
File which does not compile due to 'can't delete an incomplete type'.
Notice that function foo is not even called in here.
So compiler should try to compile this function in this unit?
If this function is not virtual or TestForward is not a template - it works.
#include "header.h"
int main (int argc, char *argv[]) {
TestForward<3> a;
return 0;
}
I know how can i fix this - by defining my deleter which is not a template, and write its definition in forward.cpp but.. I think this should work, so please help me find out why template+virtual make it not working :(
There is so much going on here that all plays together into this error ...
First, consider this: the C++ standard says that if you do this:
struct Incomplete;
void foo(Incomplete* p) { delete p; }
this is legal, but if the full definition of Incomplete turns out to have a non-trivial destructor, the program has undefined behavior. I believe this solely for compatibility with early C-like C++ programs.
So, to improve the safety of programs, the default deleter of unique_ptr uses a "safe delete", i.e. one that fails to compile for incomplete types. This means that the instantiation of the unique_ptr destructor must be aware of the full definition of the pointed-to class.
In your program, any code that uses the TestUniquePtr destructor must therefore be aware of the full definition of Forward.
TestForward::foo uses the destructor. make_ptr returns an object. foo move-constructs its own return value from this object, and then destroys the source. (In the actual generated code, this is most likely optimized away by the return value optimization, but the code must still be valid without it.)
And where/why is TestForward<3>::foo used? Well, since it is virtual, it must be instantiated whereever the vtable of the class is instantiated. And since it is a template instantiation, the vtable is instantiated wherever the constructor is called (because the constructor needs to write the vtable pointer to the object). And the constructor is called in main.
If foo is not virtual, there's no need to instantiate it. And if TestForward is not a template, I guess you put foo into some separate source file instead of the header, so the error didn't manifest for main.
So how do you fix this?
In a typical Pimpl context, you fix this by tightly controlling who instantiates the destructor of the unique_ptr. You explicitly declare the destructor of the interface class and put the definition into the source file where the impl class definition is known.
If, however, you want to hand out unique_ptrs to your incomplete class as opaque handles, you need to replace the default deleter.
// header.h
class Forward;
struct ForwardDeleter {
void operator ()(Forward* ptr);
};
using TestUniquePtr = std::unique_ptr<Forward, ForwardDeleter>;
// forward.cpp
class Forward { ... };
void ForwardDeleter::operator ()(Forward* ptr) { delete ptr; }
I am curious to know why following isn't allowed in C++?
1st program:
#include <iostream>
class Test {
public:
int myfun();
}
virtual int Test::myfun()
{ return 0; }
int main()
{ }
[Error] 'virtual' outside class declaration
2nd program:
#include <iostream>
class Test {
public:
int myfun();
};
static int myfun() {
std::cout<<"This program contains an error\n";
return 0;
}
int main() {
Test::myfun();
return 0;
}
[Error] cannot call member function 'int Test::myfun()' without object
So, my questions are
Why can't I make a member function virtual like as in 1st program?
Why can't I make a member function static like as in 2nd program?
Is there any reason to not allow these 2 keywords outside the class?
The modifiers must be on the function declarations, otherwise it would be impossible to call the functions given just the declarations.
Since they must be on the declarations, it would be redundant to put them on the definitions as well. There's no particularly good reason to disallow them (as long as they match the declaration), but no particularly good reason to allow them either.
virtual has to do with polymorphy and that is why it's only allowed inside a class. static is allowed outside of classes and makes global functions "private". The problem with your program is, is that myfun() in the class Test is not static and you have to create a instance of Test to invoke this method.
int main()
{
Test test;
test.myfun(); // works
return 0;
}
the static version of myfun() has nothing to do with the class and cannot be invoked like that: Test::myfunc() (because, as i said, it has nothing to do with Test). You can invoke it like this:
int main()
{
myfun(); // global function, has nothing to do with any classes
return 0;
}
You want to make a function virtual by stating this outside of class declaration. However, think of other code that will be using your class. You will most probably #include only the header of your Test class, which will contain only the class Test block, not the implementation. So while compiling that code the compiler will not know that a function is virtual. However, it needs to know, because it needs to generate different call code for virtual and non-virtual functions.
In more details, assume a more advanced program than your example. Following to your proposition, it will contain several compilation units and be organized, for example, as follows (#ifdef guards omitted for clarity):
// Test.h
class Test {
public:
int myfun();
};
// Test.cpp
#include "Test.h"
virtual int Test::myfunc() { return 0;}
// other.cpp
int foo(Test& test) { return test.myfunc(); } // <--- *
You will be compiling Test.cpp separately from other.cpp. So when you compile other.cpp, how would the compiler know that it should perform a virtual call to test.myfunc() in foo()?
The same reasoning applies to static functions. However, note that the static keyword has also another meaning that can be used outside of a class declaration.
The compiler compiles one source file ("translation unit") at a time. If you would declare a class
#include "Test.h"
class SpecialTest : public Test {
int myfun();
};
the compiler only sees what is in "Test.h", not what is in "Test.cpp". So if you were allowed to make myfun() virtual in the .cpp file only, the compiler could not correctly compile "SpecialTest" without having to look at "Test.cpp"
As indicated by juanchopanza in the comments, virtual only makes sense in the context ob classes. Recall that a virtual method is a function without an implementation, leaving this to other classes that inherit from the class where the virtual method is defined. But if the virtual definition is outside of a class, how to express inheritance in this case? It would be a non-implemented function without the possibility for other classes to actually implement it.
For static, you are confusing its meaning outside and inside the context of a class. If you want to have a function that can be called without the need for a corresponding object, you can define it as a static function of the class. If you want this function to be outside the class, simply omit the static as the function is available without the need for an object anyway. But static outside of the class context means something completely different.
So here's my situation: I have a class foo residing in foo.cpp with header file foo.h included in my main.cpp. I need to be able to declare a foo object as a global variable in main.cpp so that it is available to all functions within main.cpp without having to pass a reference to it every time. The problem is, foo's constructor requires a variable which isn't retrieved from the user until halfway through the main function in main.cpp. I thought I could do this this way:
static foo myFoo;
As a global variable above the main function, then after the necessary data is retrieved from the user (let's call it "variable"), I could call:
myFoo = new foo(variable);
I'm getting an error however with this:
error: no matching function for call to ‘foo::foo()’
referencing the line with static foo myFoo;
So it's basically saying that I'm trying to declare an instance of foo with a constructor taking zero arguments, when there is none.
So my question is: Is there a way to declare a label myFoo out of foo as a global variable so that the program compiles, and then later it can actually be instantiated using the constructor with a variable passed?
I know I could just do something like this:
string temp = "";
static foo myFoo(temp);
above main() and then have some function defined where I could do
myFoo.setVar(variable);
when I needed to. To me this is very ugly and necessitates the inclusion of the function setVar which has no tangible purpose other than to circumvent this very issue. Thoughts?
One option you have is to make your static instance a pointer:
static foo *myFoo = NULL;
// Later...
myFoo = new foo(variable);
Or you may want to use a default constructor and make an Init method instead.
static foo myFoo;
// Later...
myFoo.Init( variable );
When you're exposing a variable, you don't define it as static. Remove the static keyword and use extern in the header's declaration.
static foo myFoo;
That line will create a new object of type foo during the static initialization if your program. It will call the default constructor (if you don't define one, the compiler will create one for you in certain situations - you haven't posted enough code to know if that is the case here). Note that if it is defined in a header file, you will need to extern it.
Attempting to set myFoo to a pointer using
myFoo = new foo(variable);
will not compile. new foo(...) returns a foo*, not a foo. If you want it to be a pointer, you need to declare your static variable as
static foo* myFoo;
If you want it to be an object and want to set it to something other than the default, you can implement a copy-assignment operator and do something like this
foo newFoo(variable);
myFoo = newFoo;
Or provide an initialization function to change the construction values after the fact (prefer the copy-assignment in most cases as it will be less prone to errors).
I believe you might not be defining the default constructor. Once you define a constructor, the default constructor is not automatically defined. This works for me:
myclass.hpp:
#ifndef _MYCLASS_
#define _MYCLASS_
class myClass
{
public:
int I;
myClass(int i);
myClass();
};
#endif
myclass.cpp:
#include "myclass.hpp"
myClass::myClass(int i) : I(i) {};
myClass::myClass() : I(0) {};
main.cpp:
#include "myclass.hpp"
myClass myGlobalClassObject;
int main()
{
myClass myLocalClassObject(1);
myGlobalClassObject.I = 2;
return 0;
}
You are indicating that you foo object cannot be properly instantiated until halfway down the main function. This sounds like you will have an object in an inconsistent state for the first half of your main function. Very dangerous.
Anyway, there is a couple of ways to get to it:
1) If you want to create a static foo object you can use a default value for your constructor:
class foo {
public:
foo( type variable = default ) {
...
}
...
You can now declare your foo object as a global in main
foo myFoo;
and myFoo's variable will be initialised with “default”
or, without a default:
class foo {
public:
foo( type variable ) {
...
}
...
Declare your foo object as a global in main
foo myFoo(default);
Depending whether “default” makes sense in your application you can now use your myFoo object in main.cpp's functions. If “default” does not make sense you will have to add a test function before you use myFoo.
Of course you also need another member function to be able to set “variable” to your user input (something like set_variable(variable); )
2) Use a pointer. Declare a global foo * myFoo in main.cpp and test if the pointer is NULL before using it.
Now your constructor does not need a default value, it still needs the variable:
foo::foo(type variable) { ... }
You initialise your myFoo object by using: myFoo = new foo(user_input);
You can test the myFoo pointer to NULL as all uninitialised global variables are set to 0 by the startup code.
(As an aside: you do realise of course that globals are frowned upon and as such should be avoided)
Good luck
There is this code:
class SomeClass
{
public:
SomeClass(){}
SomeClass(SomeClass& b){}
SomeClass(SomeClass&b, SomeClass& c){}
};
int main()
{
SomeClass a;
SomeClass(); // works all right
//SomeClass(a); error: redeclaration of ‘SomeClass a’
SomeClass(a, a); // works all right
return 0;
}
Anonymous object of SomeClass with 0 and 2 parameters can be declared, however it cannot be declared with only 1 argument. I assume that writing
SomeClass(a);
is the same as
SomeClass a;
How to create anonymous object with one argument?
You can construct a temporary object in a statement of its own with something like:
(SomeClass)a;
or
(SomeClass(a));
As you've observed, the parentheses are needed to resolve the ambiguity between a declaration and an expression statement.
You can create that anonymouse object as the following:
(SomeClass(a));
This resolves the ambiguity since it can't be a declaration of a.
(SomeClass a); // Error: this can't be a declaration because of the parentheses
// but what else should it be?
In that context, the braces are superfluous, which means
SomeClass(a); //declaration of a
is exactly equivalent to
SomeClass a; //declaration of a
which is again equivalent to these:
SomeClass((a))); //declaration of a
SomeClass(((a))); //declaration of a
SomeClass((((a)))); //declaration of a
SomeClass(((((a))))); //declaration of a
All of these declare a variable of name a and type SomeClass.
In general, you avoid the most vexing parse by writing code with the same effect as what you wanted to write, but that can't be parsed as a declaration.
Often, this is done by adding parentheses.
In this case (SomeClass(a)); will do, or (void) SomeClass(a);
Your assumption is correct.
You simply cannot create a temporary object with a single constructor argument in a context where the same statement could be a declaration. The grammar makes it ambiguous (or, it would be ambiguous if the behaviour you're seeing weren't defined to take precedence).
Why not give the object a name, instead?
SomeClass obj(a);
Or, if you have a reason to want the object to be destroyed immediately (sometimes this is useful; e.g. a boost::this_thread::interruption_point, though that takes no arguments), you can still create a temporary but de-ambiguate the statement:
(SomeClass(a)); // the parens prevent this from being a declarative statement
In some scenarios you may also be able to use C-style casts:
(SomeClass)a;
But, hopefully, your SomeClass constructor is actually marked explicit, and we prefer not to use C-style casts anyway.
This problem doesn't arise in other contexts, ones in which a temporary might make more sense anyway:
std::cout << SomeClass(a); // *can't* be a decl of a `SomeClass` called `a`
Reading code from other posts, I'm seeing something like this.
struct Foo {
Foo() : mem(0) {}
int mem;
};
What does mem(0) {} does in this case, especially regarding the curly brackets? I have never seen this before and have no idea where else I would find out about this. I know that mem(0), would intialize mem to 0, but why the {}?
Thanks.
Since Foo() is the class' constructor, it must have a body, even if the member variable mem is initialized outside of it.
That's why, in your example, the constructor has an empty body:
Foo() : mem(0)
{
// 'mem' is already initialized, but a body is still required.
}
It defines the constructor of the class. The part after the colon is the initialization list, in which the mem member is initialized to zero using a constructor call.
Compare:
int a(0);
int b = 0;
These two do the same, but the former is more in line with how object construction typically looks in C++.
int c++ you can define your method implementation in .h file
class MyClass
{
public:
MyClass(){
.....
}
void doSomething(){
.....
}
~MyClass(){
.....
}
};
Usually it used in templates implementation. Also you could use this method of class declaration in case you would like to avoid libraries linking and you prefer to give to user all your code so he can include your file without linking any lib file to his project.