I've asked a similiar question before but now I'd like to be more specific.
The problem I face is that I have an object that contains a non copyable object and when someone wants to use my interface and he does not use it well (does try to use the object's copy constructor) he will get a compilation error that will point to the object and not his actual code.
So two questions:
1. can I fix it somehow to point it to his original code line?
2. if I cannot, how can I put a static_assert that will only happen if someone actually tries to use the copy c'tor(I've tried a few but then I get them even if someone doesn't use it...)
I am adding a sample code and the compilation error in case I was not understood...
Notice the last compile error points to the ObjectHolder h. file.. while I want it to point to the main
Thanks!
* was a mistake when I replaced names.. it is in fact the code that created the compilation error.
and Let's assume I don't want to implement a private copy c'tor just to forward the disability to copy
class NonCopyableObject
{
public:
virtual ~NonCopyableObject () {}
NonCopyableObject(int i) { m_index = i;}
int m_index;
private:
NonCopyableObject(const NonCopyableObject& other) {}
};
class ObjectHolder
{
public:
virtual ~ObjectHolder ();
ObjectHolder(int i) : obj(i) {}
NonCopyableObject obj;
};
void main()
{
ObjectHolder first(1);
ObjectHolder second(first);
}
1>------ Build started: Project: tester, Configuration: Debug Win32 ------
1> main.cpp
1>d:\users\someone\documents\visual studio 2012\projects\tester\tester\objectholder.h(13): error C2248: 'NonCopyableObject::NonCopyableObject' : cannot access private member declared in class 'NonCopyableObject'
1> d:\users\someone\documents\visual studio 2012\projects\tester\tester\noncopyableobject.h(15) : see declaration of 'NonCopyableObject::NonCopyableObject'
1> d:\users\someone\documents\visual studio 2012\projects\tester\tester\noncopyableobject.h(8) : see declaration of 'NonCopyableObject'
1> This diagnostic occurred in the compiler generated function 'ObjectHolder::ObjectHolder(const ObjectHolder &)'
The error messages supplied do not reflect the code supplied.
That aside you have an error. Considering the code:
class ObjectHolder
{
public:
virtual ~ObjectHolder ();
ObjectHolder(int i) : obj(i) {}
ObjectHolder obj;
};
How is the compiler suppose to ascertain the amount of memory required for an ObjectHolder when it is recursive?
Related
I have a base class:
#define OUT
#define NO_VTABLE __declspec(novtable)
class NO_VTABLE Foo
{
public:
virtual bool TestSomething() const = 0;
virtual bool TestSomething(OUT unsigned int& extendedInfo) const {
UNUSED(extendedInfo);
return TestSomething();
}
};
And a derived class:
class NO_VTABLE Bar : public Foo
{
public:
virtual bool TestSomething() const {
// Do the test, return the result...
}
};
Under GCC, the program compiles cleanly with -Wall -Woverloaded-virtual. Under Visual Studio, I get a dirty compile. TestSomething from above is Available shown below.
1> ...\derived.h(78) : warning C4266: 'bool DeviceState::Available(unsigned int &) const' :
no override available for virtual member function from base 'DeviceState'; function is hidden
1> ...\base.h(794) : see declaration of 'DeviceState::Available'
1> ...\base.h(787) : see declaration of 'DeviceState'
Removing NO_VTABLE makes no difference. The warning persists.
All the TestSomething are public and virtual in both the base and derived classes, so its not clear to me what is hidden from the caller.
I'm working through testing under Visual Studio, and I've encountered it on both Visual Studio 2005, 2008 and 2010. I still have other VS's to test, but at this point, I know its not a one-off.
I prefer not to turn off the warning because the file base.h is large with lots of classes, and it might encounter other problems in the future.
What does Visual Studio claim is hidden from the caller? What is the source of the warning under Visual Studio, and how do I clear it?
If you look up error C4266 you'll find that it says A derived class did not override all overloads of a virtual function. So for this compiler you'll need to override all of the overloads for the unsigned int & variant to be visible.
I haven't looked up in the language spec to see if this is conforming or not.
I'm making a server interface for network programming and I ran into a problem. I want to make a server object uncopyable, mostly because it doesn't really make sense to do so and would probably make problems, and also because it uses threads which can't be copied. However, when I make the copy constructor and assignment operator private, I get an error:
Error 2 error C2248: '(namespaces..)::Server::Server' : cannot access private member declared in class '(namespaces..)::Server' (path..)\type_traits 1545 1 Server
The error seems to be in the type_traits file? I haven't used it at all, though it might be possible that some of the other std files I'm including use it? I'm using iostream, sstream, string, thread, map.
Here's the server class definition:
class DLL_PUBLIC Server
{
public:
Server(unsigned int);
~Server();
(...)
private:
class PvtImpl; //Private implementation, so it isn't seen in the header file
PvtImpl *pvtImpl;
Server(const Server &par_other){}
Server& operator=(const Server &par_other){ return *this; }
(...)
};
and the private implementation:
class Server::PvtImpl
{
public:
bool running;
unsigned int port, backlog, currentlyConnected;
SOCKET listenSocket;
std::thread *acceptConnectionsThread;
std::thread* *receiveDataThreads; //I am using pointers instead of vectors because I want it to be fixed
ClientObj* *clients;
std::map<ClientObj*, unsigned int> clientIndexMap;
};
Since I don't know what code to post because I don't even know where the error is coming from, then tell me if you need a specific part of it posted. If I comment out the private copy constructor and assignment operator then it works, but I don't want this to be copyable and especially not through default constructor. Doubt it, but does it have something to do with it being a DLL?
Anyway that's it, thanks for your time
Update
So I added a = delete to the constructor as suggested, and also made it public:
class DLL_PUBLIC Server
{
public:
Server(unsigned int);
Server(const Server &par_other) = delete;
~Server();
Server& operator=(const Server &par_other) = delete;
(...)
};
I am getting a bit of a different error now, but also in the type_traits file:
Error 2 error C2280: '(namespaces..)::Server::Server(const (namespaces..)::Server &)' : attempting to reference a deleted function (path..)\type_traits 1545 1 Server
A bit of code it is complaining about in that file:
// TEMPLATE FUNCTION _Decay_copy
template<class _Ty> inline
typename decay<_Ty>::type _Decay_copy(_Ty&& _Arg)
{ // forward _Arg as value of decayed type
return (_STD forward<_Ty>(_Arg));
}
_STD_END
Update 2
So this is the output window from VS as requested:
1>(path...)\type_traits(1545): error C2280: '(namespaces..)::Server::Server(const (namespaces..)::Server &)' : attempting to reference a deleted function
1> (path..)\Server.h(19) : see declaration of '(namespaces..)::Server::Server'
1> (path..)\thread(47) : see reference to function template instantiation '(namespaces..)::Server std::_Decay_copy<(namespaces..)::Server&>(_Ty)' being compiled
1> with
1> [
1> _Ty=(namespaces..)::Server &
1> ]
1> Server.cpp(94) : see reference to function template instantiation 'std::thread::thread<void(__cdecl &)(const (namespaces..)::Server &),(namespaces..)::Server&>(_Fn,(namespaces..)::Server &)' being compiled
1> with
1> [
1> _Fn=void (__cdecl &)(const (namespaces..)::Server &)
1> ]
The line 19 in the Server.h it's mentioning is the copy constructor declaration. Line 94 in Server.cpp is thread creation:
pvtImpl->acceptConnectionsThread = new std::thread(acceptConnections, *this);
The acceptConnections function takes the server by constant reference so it shouldn't copy, here's the declaration:
friend void acceptConnections(const Server&);
Your problem is most likely in the thread constructor:
pvtImpl->acceptConnectionsThread = new std::thread(acceptConnections, *this);
Try this instead:
pvtImpl->acceptConnectionsThread = new std::thread(acceptConnections, std::ref(*this));
because without the std::ref() wrapper, a copy of your server instance will be passed into the thread constructor, which in turn will pass that copy by reference to your acceptConnections() method. Or at least try to, but it never got that far, as the compiler failed the initial copy.
template<class CharType>
struct MyString
{
MyString()
{}
MyString(CharType*)
{}
};
int main()
{
char* narrow_str = 0;
MyString<char>(narrow_str); // error C2040
}
My compiler is VC++ 2013 RC.
The simplest code cannot be compiled because of the error C2040.
error C2040: 'narrow_str' : 'MyString' differs in levels of
indirection from 'char *'
Why?
The problem is this is actually not being parsed as a constructor call but as a variable definition. The problem is you already defined a variable narrow_str. You may have already known this but you can easily fix this by giving it a name.
template<class CharType>
struct MyString
{
MyString()
{}
MyString(CharType*)
{}
};
int main()
{
char* narrow_str = 0;
MyString<char> ns(narrow_str); // error C2040
}
BTW this is also the source of the most vexing parse which occurs when this type of syntax is used in a function argument.
To be honest though I'm surprised that you got a different error because both g++ and clang gave me a clear error.
your syntax in creating a struct is wrong .
change
MyString<char>(narrow_str); // error C2040
to
MyString<char> myString(narrow_str);
will be ok.
I am trying to compile a file which defines a garbage collection template and several supporting classes with use of operator overloading. I've tried to run this through MSVC++ 2008, and the compile stops at this particular class:
// (The collector defines gc_object_generic_base which
// inherits from gc_object_generic_base and optionally adds
// collector-specific properties.)
template<class garbage_collector>
class gc_object_base : public garbage_collector::gc_object_collector_base {
public:
gc_object_base() {
garbage_collector::constructing_gc_object_base(this);
}
static void* operator new(size_t sz,
block_construction_locker_base* lock = block_construction_locker<garbage_collector>().get_this())
{
return garbage_collector::allocate(sz, lock);
}
static void operator delete(void* p, block_construction_locker_base* lock) {
return garbage_collector::deallocate(p);
}
static void operator delete(void* p) {
return garbage_collector::deallocate(p);
}
private:
// TODO: are arrays worth implementing?
static void* operator new[](size_t sz) {
assert(0);
return 0;
}
};
Truncated output for brevity's sake:
2>------ Build started: Project: Test, Configuration: Debug Win32 ------
2>Compiling...
2>FlashTest.cc
2>C:\test\gameswf\base\tu_gc.h(133) : error C2059: syntax error : 'string'
2> C:\test\gameswf\base\tu_gc.h(151) : see reference to class template instantiation 'tu_gc::gc_object_base' being compiled
2>C:\test\gameswf\base\tu_gc.h(135) : error C2091: function returns function
2>C:\test\gameswf\base\tu_gc.h(135) : error C2802: static member 'operator new' has no formal parameters
2>C:\test\gameswf\base\tu_gc.h(135) : error C2333: 'tu_gc::gc_object_base::operator new' : error in function declaration; skipping function body
Any ideas on where I should start looking at?
I just had the same pattern of errors in a different project. It seems to happen when someone has done this somewhere:
#define new new(someArgs, someMoreArgs, etc)
It's targeted at simple 'new' expressions, but it breaks down if anyone tries to declare any more 'operator new' thingies.
In the opening lines
template<class garbage_collector>
class gc_object_base : public garbage_collector::gc_object_collector_base {
garbage_collector appears twice here, once as the template parameter and another as an outer-class to gc_object_collector_base, but as it is a template parameter does it not require "typename" here thus:
template<class garbage_collector>
class gc_object_base : public typename garbage_collector::gc_object_collector_base {
There is no mention of string in your code, that I can see. But I would start by ensuring that you first #include <string> before your class delcaration, and then make sure you use std::string as your declarator, rather than just string.
class messageA {
};
class messageB {
};
template<class T>
class queue {
public:
virtual ~queue() {}
void submit(T& x) {}
};
class A : public queue<messageA>, public queue<messageB>
{
};
int main()
{
A aa;
aa.submit(messageA());
aa.submit(messageB());
}
My first thought is, the above code should be fine, as class A will contains 2 overloaded submit functions, which will accept messageA and messageB object.
However, the compiler gives me the following error :
May I know why there is an ambiguous? Isn't it is quite obvious that, for the 1st submit call, I want to call messageA version? For the 2nd submit call, I want to call messageB version?
------ Build started: Project: main, Configuration: Release Win32 ------
Compiling...
main.cpp
.\main.cpp(21) : error C2385: ambiguous access of 'submit'
could be the 'submit' in base 'queue<messageA>'
or could be the 'submit' in base 'queue<messageB>'
.\main.cpp(21) : error C3861: 'submit': identifier not found
.\main.cpp(22) : error C2385: ambiguous access of 'submit'
could be the 'submit' in base 'queue<messageA>'
or could be the 'submit' in base 'queue<messageB>'
.\main.cpp(22) : error C2664: 'queue<T>::submit' : cannot convert parameter 1 from 'messageB' to 'messageA &'
with
[
T=messageA
]
.\main.cpp(22) : error C3861: 'submit': identifier not found
I have no compiler right now, but I guess one inheritance could hide the other : The compiler will use Koenig Lookup to find the right symbol, and if I remember correctly, once the compiler find a suitable symbol (i.e., a method called "submit"), it will stop searching for others in parent and/or outer scopes.
In this case, I thought both inheriting classes would be searched for the symbol, but without your exact compiler (Visual C++ 2003 ? 2008 ? 2010 ?), I cannot guess much more.
After some thoughts, another possibility is that the compiler did find both symbols, but is unable to decide which to call (at that moment of symbol resolution, the compiler cares only for symbol name, not its exact prototype). I believe this last explanation to be the right one.
Try adding using statements in your derived classes :
class A : public queue<messageA>, public queue<messageB>
{
using queue<messageA>::submit ;
using queue<messageB>::submit ;
} ;
to bring both the submit methods directly in the A class scope.
Note, too, that your submit methods are taking messages as non-const reference, while in the constructor, your message parameters are temporaries (and thus, const r-values).
Re-writting the main as:
int main()
{
A aa;
messageA mA ;
messageA mB ;
aa.submit(mA);
aa.submit(mB);
}
could help compile (this could explain the compiler error on line 22).
Or you could change the prototype of your submit methods to accept const references instead of non-const references.
Note: Still without compiler, so trying to brain-debug your code... :-P ...
Something* smth1 = ((Base<Something> *)d)->createBase<Something>();
The above code works fine.