I have two classes say foo and bar. The constructor of foo is private so as to only allow the bar class to instantiate it.
// foo.h
class foo
{
friend class bar;
private:
foo()
{}
};
// bar.h
class bar
{
public:
bar()
{
foo* f = new foo();
}
};
Also I am using boost::shared_ptr however for simplicity I did not mention it here
However when I attempt to build the program I get the error
In instantiation of ‘typename boost::detail::sp_if_not_array::type
boost::make_shared() [with T = bar; typename
boost::detail::sp_if_not_array::type = boost::shared_ptr]’:|
/home/..../Projects/CodeBlocks/../bar.cpp|18|required from here|
/home/..../Projects/CodeBlocks/../foo.h|23|error: ‘foo::foo()’ is
private| ||=== Build finished: 1 errors, 2 warnings (0 minutes, 5
seconds) ===|
Is it because bar.h gets built first? If so, any suggestions on how to fix this?
I am using boost::shared_ptr however for simplicity I did not mention it here
Ironically, that is the very thing that's making your code fail to compile. Without it, the example you've shown compiles without errors.
The problem is that you're trying to use boost::make_shared to create the shared_ptr. This will lead to make_shared attempting to construct a foo, which of course fails, because you've declared bar to be a friend of foo's, but make_shared isn't a friend.
Use the shared_ptr constructor directly instead, and pass it a pointer to a foo object that has been allocated by bar.
Live demo
Note that declaring boost::make_shared as a friend is not a reliable solution either because it may delegate the actual construction to some other function.
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 have been playing around with some c++ template meta-programing and I have discovered situation which I think is rather peculiar.
Let say I have the following class.
template<typename T>
class Foo{
};
Then later I found I use a foward declaration of a class (I am assuming that is what it is being treated as) as the template argument as so
Foo<class bar> bar1;
I also found that the following also compile fine.
Foo<class bar()> bar2;
Foo<class bar(int a)> bar3;
So my question is, why does this work. What is going on in all three cases.
According to the standard I can not declare a class at this point so this fails:
Foo<class bar{}> bar4
My original assumption was this just a forward declaration and you could actually declare a class at that pointer (which I could see possible uses for).
However, you can not. So my second question what is the use of above? Is there any practical uses of it or is just a result of how c++ works that this is legal. One use I can see is you can use this to create tagging information on a type.
I am using the most recent version of g++
In all 3 cases, you are forward declaring the class bar, so you have to define it later one.
Foo<class bar> bar1;
This works because it is allowed to declare a class for the first time in a template argument, i.e. it is equivalent to
class bar;
Foo<bar> bar1;
Foo<class bar()> bar2;
This creates the class bar, just as before, and creates a function taking no parameters and returning a bar.
Foo<class bar(int a)> bar3;
This is really similar to the second one, just that here, it declares a function taking an int, instead of none. It is equivalent to
class bar;
Foo<bar(int)> bar3;
The language expects a type in Foo< ... >. What you're providing is an "incomplete type" (bar isn't defined yet), but that's fine because T isn't actually used anywhere in your template.
C++ allows the syntax class bar to refer to a class bar for compatibility with C, where you had to say struct bar to refer to a type defined as struct bar { ... };. In C++, the struct/class keyword is optional if the compiler already knows that bar is a class.
class bar() and class bar(int a) are function types. They mean bar () and bar (int) respectively, i.e. a function (taking no arguments / taking an int) returning a bar.
The code below compiles, even though I was expecting the compiler to complain that it doesn't know the size of Foo. However, if I replace the #include with a forward declaration of Bar, it doesn't compile for this reason.
I know that Foo is definitely only forward declared because if Foo* myfoo; is changed to Foo myfoo; then it does not compile. Why does this error only occur with a vector of objects of one type, but not the other?
Using Visual Studio Express 2013.
#include "Bar.h"
class Foo;
class MyClass{
Foo* myfoo;
std::vector<Foo> foos;
std::vector<Bar> bars;
};
In and of themselves, there is no reason that template type arguments need to be complete types (in fact, 14.3.1/2 explicitly states that this is not the case).
Such a requirement then comes from how that type is used within the definition of your type template (in this case, std::vector). For example, [C++11: 20.7.1/5] states that the template argument T of a std::unique_ptr<T> may be incomplete at the point of the unique_ptr's declaration; this is stated explicitly because it was not the case for std::auto_ptr.
You'll find that as soon as you try to do pretty much anything with your vector, you'll need that T to be complete. This issue is detectable at compile-time as it all comes down to the instantiation of templates, so your compiler will do the appropriate erroring as and when required.
The vector's destructor is usually one of those things.
So, using GCC 4.8, I cannot instantiate either vector with an incomplete value_type:
#include <vector>
class Foo;
class Bar;
std::vector<Foo> foos;
std::vector<Bar> bars;
int main() {}
error: invalid use of incomplete type 'class Foo'
error: invalid use of incomplete type 'class Bar'
Only when I use them as members in a class that never gets used is the entire thing compilable, because the vectors' destructors are never invoked and therefore never template-instantiated:
#include <vector>
class Foo;
class Bar;
class T
{
std::vector<Foo> foos;
std::vector<Bar> bars;
};
int main() {}
(no error)
Whatever your implementation does, it'll be the same for both Foo and Bar; if you're seeing a difference between them, then you must be doing something different with Bar that you have not shown us.
(I know its already answered, but I'm going to post mine any way)
A good way to think of this is, when does the definition of the class need to be known? In the case of vector<Foo>, the sizeof(Foo) needs to be known at reserve time, or access time, and the Foo::constructor and Foo::destructor information needs to be known when we add or remove items to the vector. And of course, it needs the Foo::destructor when the vector is being destroyed.
So this leads to one of the more common problems with forward declared template arguments to std::vector: you have a class above that uses a default constructor and a default destructor. When is the default destructor defined? Well (semantically, atleast) its defined when you don't define it in the class, so it is defined in this header file. More to the point, what is in that destructor? Hidden in every C++ destructor is clean up code that goes beyond the body of the destructor: it calls all the destructors of all members...but that means it tries to call the destructor for std::vector.
Are you SOL? Nope. The following should work just fine for you.
//myclass.hpp
class Foo;
class Bar;
class MyClass{
public:
MyClass();
~MyClass();
Foo* myfoo;
std::vector<Foo> foos;
std::vector<Bar> bars;
private:
};
//myclass.cpp
#include "myclass.hpp"
#include "Bar.h"
#include "Foo.h"
MyClass::MyClass(){};
MyClass::~MyClass(){};
Apparently C++ lets you define both a struct/class and a function with the same name like this:
struct Foo {
int foo;
Foo(int foo) : foo(foo) {}
};
void Foo(int foo) {}
int main() {
// Works, calls function
Foo(42);
// Doesn't work - compiler error
Foo foo(42);
}
Is this the expected behaviour?
How to create a instance of the Foo struct?
How to avoid that some added library defining a function named like a type in your project causes compiler errors all over the place?
You can write struct or class when you mean the type:
struct Foo foo(42);
class Foo bar(0xdeadbeef);
Yes, this is expected. There is no general way to say "I meant the class, not the function, with this name" because you are not supposed to re-use names.
typename cannot help you here, though since Foo is a class and C++ provides backward compatibility with C's struct T type syntax, you can say class Foo or struct Foo instead:
int main() {
// Calls function
Foo(42);
// Constructs a `[class] Foo`
class Foo foo(42);
}
This is something of a hack, though, and doesn't really solve the fundamental problem which is that the symbols in your program are not clearly differentiated from one another.
Depending on your real circumstances, a namespace might solve your problem in a robust and clear way. Libraries should be using them (but often don't).
Otherwise simply improve your names... and I don't mean by calling one Foo and the other FooClass!
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