Cannot make an object uncopyable - c++

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.

Related

Problem overloading assignment operator in template class

Using the MS command line C++ compiler, version as indicated in the output below, compiling the following fails with the compiler report as included:
// File: shared_memory.h
template <class Contents>
class SharedMemory {
public:
...
operator Contents& () {
...
}
...
SharedMemory &operator= (Contents &contents) { // [EDIT] CONST REMOVED AT PARAMETER
...
}
...
};
// File: shared_memory_test.cpp
class SharedAnimals: public SharedMemory <Animals> {
...
using SharedMemory <Animals>::operator=; // [EDIT] HAD TO BE ADDED
...
}; // This is line 67 in the original code
int main (int argc, char** argv) {
...
Animals animals (kind);
...
sharedAnimals = animals; // This is line 93 in the original code
...
}
// Compiler reports:
shared_memory_test.cpp
C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Tools\MSVC\14.16.27023\include\xlocale(319): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
shared_memory_test.cpp(93): error C2679: binary '=': no operator found which takes a right-hand operand of type 'Animals' (or there is no acceptable conversion)
shared_memory_test.cpp(67): note: could be 'SharedAnimals &SharedAnimals::operator =(SharedAnimals &&)'
shared_memory_test.cpp(67): note: or 'SharedAnimals &SharedAnimals::operator =(const SharedAnimals &)'
shared_memory_test.cpp(93): note: while trying to match the argument list '(SharedAnimals, Animals)'
Can anyone give me a hint on what I am doing wrong?
[EDIT]
Indeed the answer at Assignment operator inheritance provided by user1810087 solved the problem.
While the answer is already there, the context of this question, namely using a template class, led me to believe that the error was connected to that, and did not look for questions relating to "assignment operator inheritance".
Since I may not be the only one running into this, I suggest this question be maintained.

C++ Nvidia PhysX cannot convert PxFoundation to shared_ptr<>

Im trying to create a PxFoundation and save it in my member variable "foundation" which is a std::shared_ptr. However upon creating the object I get this:
C2440: '<function-style-cast>': cannot convert from 'physx::PxFoundation *' to 'std::shared_ptr<physx::PxFoundation>'
How can I put the raw pointer from the PxCreateFoundation function into a shared_ptr? as I'm not calling the ctor of any PhysX class I cannot use std::make_shared, so using the normal std::shared_ptr<>() constructor seems my only option?
Code:
#include <memory>
#include <PxPhysics.h>
#include "PhysXErrorCallback.hpp"
#include "PhysXDefaultAllocator.hpp"
#include <foundation/PxFoundationVersion.h>
class PhysicsEngine
{
public:
PhysicsEngine();
std::shared_ptr<physx::PxFoundation> foundation;
static PhysXErrorCallback gDefaultErrorCallback;
static PhysXDefaultAllocator gDefaultAllocatorCallback;
};
PhysicsEngine::PhysicsEngine()
{
foundation = std::shared_ptr<physx::PxFoundation>(PxCreateFoundation(PX_FOUNDATION_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback));
}
EDIT:
After chaning the
foundation = std::shared_ptr<physx::PxFoundation>(...)
to
foundation.reset(...)
it now gives me these errors:
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\memory(1519): error C2440: '<function-style-cast>': cannot convert from 'physx::PxFoundation *' to 'std::shared_ptr<physx::PxFoundation>'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\memory(1519): note: No constructor could take the source type, or constructor overload resolution was ambiguous
1>physicsengine.cpp(25): note: see reference to function template instantiation 'void std::shared_ptr<physx::PxFoundation>::reset<physx::PxFoundation>(_Ux *)' being compiled
1> with
1> [
1> _Ux=physx::PxFoundation
1> ]
1>physicsengine.cpp(25): note: see reference to function template instantiation 'void std::shared_ptr<physx::PxFoundation>::reset<physx::PxFoundation>(_Ux *)' being compiled
1> with
1> [
1> _Ux=physx::PxFoundation
1> ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\memory(1519): error C2228: left of '.swap' must have class/struct/union
EDIT2:
Heres the PxCreateFoundation declaration and definition:
PX_C_EXPORT PX_FOUNDATION_API physx::PxFoundation* PX_CALL_CONV
PxCreateFoundation(physx::PxU32 version, physx::PxAllocatorCallback& allocator, physx::PxErrorCallback& errorCallback);
physx::PxFoundation* PxCreateFoundation(physx::PxU32 version, physx::PxAllocatorCallback& allocator,
physx::PxErrorCallback& errorCallback)
{
return physx::shdfnd::Foundation::createInstance(version, errorCallback, allocator);
}
PxFoundation class:
/**
\brief Foundation SDK singleton class.
You need to have an instance of this class to instance the higher level SDKs.
*/
class PX_FOUNDATION_API PxFoundation
{
public:
virtual void release() = 0;
protected:
virtual ~PxFoundation()
{
}
};
createInstance definition:
Foundation* Foundation::createInstance(PxU32 version, PxErrorCallback& errc, PxAllocatorCallback& alloc)
{
//...
mInstance = reinterpret_cast<Foundation*>(alloc.allocate(sizeof(Foundation), "Foundation", __FILE__, __LINE__));
if(mInstance)
{
PX_PLACEMENT_NEW(mInstance, Foundation)(errc, alloc);
return mInstance;
}
//...
}
Seems like I found the error:
Most destructors in PhysX SDK are not public. Therefore trying to create a smart pointer with one of these classes results in an error.
Only other option beside using a raw pointer would be to create a custom deleter:
auto foundation = std::shared_ptr<physx::PxFoundation>(PxCreateFoundation(PX_FOUNDATION_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback), [=](physx::PxFoundation* f)
{
f->release();
});
Your foundation = line isn't actually calling a constructor. It's trying to cast the raw pointer to a shared_ptr using the syntax called a "functional cast" or "function-style cast" (#2 here), and then assign the result to the foundation variable (which has already been default-constructed). That won't work because shared_ptr has no cast from a raw pointer (to prevent it from accidentally taking ownership of things it shouldn't).
The best way to fix the problem is to use your constructor's initializer list to actually initialize foundation with the pointer:
PhysicsEngine::PhysicsEngine() :
foundation(PxCreateFoundation(PX_FOUNDATION_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback))
{
// empty
}
This passes the pointer to foundation's constructor, as opposed to letting foundation be default-constructed and then assigning to it afterward in the constructor body. But if you really need to do it by assignment for some reason, you can use the reset function to tell foundation to take ownership of the pointer:
PhysicsEngine::PhysicsEngine()
{
foundation.reset(PxCreateFoundation(PX_FOUNDATION_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback));
}

Can't declare ifstream class member in header file

I am trying to declare an ifstream object in a header file as is shown but I get an error saying that it cannot be accessed. I have tried various things such as making it into a pointer instead, initialising in the .c file etc. but my code can't seem to get part the declaration of it.
ReadFile.h:
#ifndef READFILE_H
#define READFILE_H
#include "cv.h"
#include "highgui.h"
#include <iostream>
#include <fstream>
class ReadFile{
private:
std::ifstream stream;
public:
std::string read();
ReadFile(); // Default constructor
~ReadFile(); // Destructor
};
#endif
ReadFile.c:
#include "ReadFile.h"
ReadFile::ReadFile(){
stream.open("./data.txt");
}
ReadFile::~ReadFile(){
stream.close();
}
The error that I am getting is:
Error 9 error C2248: 'std::basic_ifstream<_Elem,_Traits>::basic_ifstream' : cannot access private member declared in class 'std::basic_ifstream<_Elem,_Traits>' c:\users\Bob\documents\project\models\readfile.h 23 1 Project
The output is:
1>c:\users\Bob\documents\project\models\readfile.h(23): error C2248: 'std::basic_ifstream<_Elem,_Traits>::basic_ifstream' : cannot access private member declared in class 'std::basic_ifstream<_Elem,_Traits>'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\fstream(827) : see declaration of 'std::basic_ifstream<_Elem,_Traits>::basic_ifstream'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> This diagnostic occurred in the compiler generated function 'ReadFile::ReadFile(const ReadFile &)'
The error occurs when std::ifstream stream; is included and will disappear when this line is removed. What could be causing this error? Have I missed something really obvious or is there more to it?
The problem is that std::ifstream doesn't have a public copy constructor (because copying one wouldn't make sense) but the compiler-generated copy constructor for your class wants to use it.
It doesn't have any available assignment operator for the same reason (i.e. copying a std::ifstream is nonsense).
You should disallow copying and assignment for your class as well.
A simple way is to add
private:
ReadFile(const ReadFile&);
ReadFile& operator=(const ReadFile&);
to your class, if you're using C++03.
In C++11, use the = delete syntax.
public:
ReadFile(const ReadFile&) = delete;
ReadFile& operator=(const ReadFile&) = delete;
This isn't an answer per se, but in case anyone comes across this question in the future after struggling as much as I just have, I decided to post it anyway.
I was facing a very similar issue to the OP for basically the same reason, although the error message that Visual C++ was giving me was 'ClassName::ClassName(const ClassName &)': attempting to reference a deleted function. In my inexperienced mind, I was thinking "WTF, I'm not copying or assigning any copies anywhere!".
However, after an hour of screaming at the computer in frustration I was able to narrow the problem down to the ifstream class member, which led me here. And thanks to the accepted answer, I was able to narrow the problem down even further to this single line of code:
list.emplace_back(objParam);
Little did I know that std::vector objects need a copy constructor defined on their template parameter's type in order to reserve space for future emplace_back() calls and the like!
So the solution comes from this SO answer courtesy of Bryan Chen (emphasis added by me):
So you can see emplace_back does use the desired constructor to create the element and call copy constructor when it need to grow the storage. You can call reserve with enough capacity upfront to avoid the need to call copy constructor.
Full credit and many thanks go to Bryan and molbdnilo for leading me to this discovery.

Why won't std::shared_ptr accept my deleter function object?

I'm have a problem with *passing a deleter functor into a std::smart_ptr*. This is the first time I've tried anything like this, so I may be overlooking something very simple..
Here's what my functor class looks like;
#pragma once;
#ifndef ASSETDELETERS_H
#define ASSETDELETERS_H
#include "RenderSystem.h"
struct SourceImageDeleter
{
RenderSystem & refGraphicsRenderer;
unsigned int * ptrTextureID;
explicit SourceImageDeleter( RenderSystem & tempRef, unsigned int * tempPtrID )
: refGraphicsRenderer( tempRef ) ,
ptrTextureID(tempPtrID) {};
SourceImageDeleter( const SourceImageDeleter & originalCopy )
: refGraphicsRenderer( originalCopy.refGraphicsRenderer ) ,
ptrTextureID( originalCopy.ptrTextureID ) {};
void operator() ()
{
refGraphicsRenderer.deregisterTexture( ptrTextureID );
}
};
#endif
The RenderSystem::deregisterTexture function only requires one argument (unsigned int *), because of that, it's being passed at the creation of the functor. I've looked into the use of std::bind, but I don't have much experience with that and wasn't able to have much success using it instead of making a functor.
And here's the only method that uses it so far..
std::shared_ptr<SourceImage> Engine::createSourceImage( std::string tempFilepath )
{
SourceImage * tempImagePtr = new SourceImage( tempFilepath );
registerTexture( &tempImagePtr->textureID, &tempImagePtr->image );
return std::shared_ptr<SourceImage>( tempImagePtr , SourceImageDeleter( this->graphicsRenderer, &tempImagePtr->textureID ) );
}
I'm not sure why it's not working! I've basically been trying to have my smart_ptr run a custom deletion function all week, and between trying to figure out how pointers-to-method passing works, how std::bind/std::mem_fun_ref works, and how functors work has been stumping me all week..
Anyway, here's the compile error that Visual Studio has been giving me, I hope someone can help me figure out what I've been screwing up;
error C2064: term does not evaluate to a function taking 1 arguments
1> class does not define an 'operator()' or a user defined conversion operator to a pointer-to-function or reference-to-function that takes appropriate number of arguments
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\memory(1438) : see reference to function template instantiation 'void std::tr1::shared_ptr<_Ty>::_Resetp<_Ux,_Dx>(_Ux *,_Dx)' being compiled
1> with
1> [
1> _Ty=SourceImage,
1> _Ux=SourceImage,
1> _Dx=SourceImageDeleter
1> ]
1> c:\projects\source\engine.cpp(151) : see reference to function template instantiation 'std::tr1::shared_ptr<_Ty>::shared_ptr<SourceImage,SourceImageDeleter>(_Ux *,_Dx)' being compiled
1> with
1> [
1> _Ty=SourceImage,
1> _Ux=SourceImage,
1> _Dx=SourceImageDeleter
1> ]
(By the way, engine.cpp(151) is the return line inside Engine::createSourceImage shown above.. If I remove the deleter argument, the program compiles and runs fine aside from the obvious resource leaks associated with improper image deletion..)
std::shared_ptr passes in the pointer being deleted to the deleter, which is exactly what your error message says: the class does not define an operator() with the correct number of arguments.
Your deleter isn't expecting any parameters, so it won't work; you'll need to change it to void operator()(SourceImage*)

Compilation warning for Objects that contain non Copyable objects are unreadable

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?