I try to create a singleton object using shared_ptrs. However the code does not compile when the constructors/destructor are private for the specific object
The code is below.h
//ThreadPool.h
class ThreadPool
{
public:
static std::shared_ptr<ThreadPool> & getInstance();
inline static std::shared_ptr<ThreadPool> m_threadPoolInstance;
private:
ThreadPool() =default;
~ ThreadPool() = default;
ThreadPool(ThreadPool const &) = default;
};
//ThreadPool.cpp
#include "pch.h"
#include <ThreadPool.h>
std::shared_ptr<ThreadPool> & ThreadPool::getInstance()
{
if (! m_threadPoolInstance)
{
ThreadPool * p_ThreadPool = new ThreadPool();
m_threadPoolInstance.reset(p_ThreadPool);
}
return m_threadPoolInstance;
}
I am using VS17 compiler
The error that is created is the following
error C2440: '': cannot convert from '_Ux *' to
'std::shared_ptr'
with
[
_Ux=ThreadPool
] include\memory(1462): note: No constructor could take the source type, or constructor overload resolution was ambiguous
threadpool.cpp(9): note: see reference to function template
instantiation 'void std::shared_ptr::reset(_Ux
*)' being compiled
with
[
_Ux=ThreadPool
] threadpool.cpp(9): note: see reference to function template instantiation 'void std::shared_ptr::reset(_Ux
*)' being compiled
with
[
_Ux=ThreadPool
]
When I set the constructors/destructor in public section, the compilation is succesfull.
However running the same code using gcc compiler , compiles succesfully
The conversion fails because your ThreadPool class has a private destructor.
Calling .reset(ptr) will use the delete expression (delete ptr;) as the deleter, which requires that the destructor be public.
Refer to overload (2) here: https://en.cppreference.com/w/cpp/memory/shared_ptr/reset
2-4) Replaces the managed object with an object pointed to by ptr. Y must be a complete type and implicitly convertible to T. Additionally:
2) Uses the delete expression as the deleter. A valid delete expression must be available, i.e. delete ptr must be well formed, have well-defined behavior and not throw any exceptions. Equivalent to shared_ptr(ptr).swap(*this);.
You either need to make the destructor public or provide a custom deleter.
Related
Header:
CChristianLifeMinistryHtmlView m_pHtmlView = nullptr;
Source:
m_pHtmlView = new CChristianLifeMinistryHtmlView();
Trying to change it to use a smart pointer. I can do this (inside OnInitDialog):
auto m_pHtmlView2 = std::make_unique<CChristianLifeMinistryHtmlView>;
But I can't work out how to have my smart pointer defined as a member variable of my CDialog class. I can't do: std::unique_ptr m_pHtmlView2.
I saw this discussion (Using smart pointers as a class member) and based on that I tried this in the header:
//CChristianLifeMinistryHtmlView *m_pHtmlView;
std::unique_ptr<CChristianLifeMinistryHtmlView> m_pHtmlView;
But that will not compile:
6>C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.30.30704\include\memory(3087,1): error C2248: 'CChristianLifeMinistryHtmlView::~CChristianLifeMinistryHtmlView': cannot access protected member declared in class 'CChristianLifeMinistryHtmlView'
6>D:\My Programs\2022\MeetSchedAssist\Meeting Schedule Assistant\ChristianLifeMinistryHtmlView.h(104): message : compiler has generated 'CChristianLifeMinistryHtmlView::~CChristianLifeMinistryHtmlView' here
6>D:\My Programs\2022\MeetSchedAssist\Meeting Schedule Assistant\ChristianLifeMinistryHtmlView.h(22): message : see declaration of 'CChristianLifeMinistryHtmlView'
6>C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.30.30704\include\memory(3085): message : while compiling class template member function 'void std::default_delete<CChristianLifeMinistryHtmlView>::operator ()(_Ty *) noexcept const'
6> with
6> [
6> _Ty=CChristianLifeMinistryHtmlView
6> ]
6>C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.30.30704\include\memory(3195): message : see reference to function template instantiation 'void std::default_delete<CChristianLifeMinistryHtmlView>::operator ()(_Ty *) noexcept const' being compiled
6> with
6> [
6> _Ty=CChristianLifeMinistryHtmlView
6> ]
6>C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.30.30704\include\memory(3122): message : see reference to class template instantiation 'std::default_delete<CChristianLifeMinistryHtmlView>' being compiled
6>D:\My Programs\2022\MeetSchedAssist\Meeting Schedule Assistant\AvailableBrothersReportPreview.h(52): message : see reference to class template instantiation 'std::unique_ptr<CChristianLifeMinistryHtmlView,std::default_delete<CChristianLifeMinistryHtmlView>>' being compiled
Update
Based on the advice in the comments I now have:
Header:
std::unique_ptr<CChristianLifeMinistryHtmlView> m_pHtmlView;
Source (in OnInitDialog):
m_pHtmlView = std::make_unique<CChristianLifeMinistryHtmlView>();
if (m_pHtmlView != nullptr)
{
m_pHtmlView->Create(nullptr, nullptr, AFX_WS_DEFAULT_VIEW,
m_rctPreviewHtml, this, 0);
m_pHtmlView->ShowWindow(SW_SHOWNORMAL);
if(CMeetingScheduleAssistantApp::WaitForFileToBeReady(m_strTempHtmlFile))
m_pHtmlView->Navigate2(m_strTempHtmlFile, 0, nullptr);
}
It complies and works. My popup dialog displays and the CHtmlView derived control is visible. Cool. But when I click OK to close the dialog I get an exception:
How do we address that?
CHtmlView is derived from CFormView -> CView, which deletes itself in CView::PostNcDestroy with delete this; So the memory is already managed.
Replace new with std::make_unique, and call release() immediately, because you don't want unique_ptr to delete it anymore.
//m_pHtmlView = new CChristianLifeMinistryHtmlView();
m_pHtmlView = std::make_unique<CChristianLifeMinistryHtmlView>().release();
If you had written new and delete in your original code (that also means you at least override CMyHtmlView::PostNcDestroy) then unique_ptr can be used to replace both new and delete.
In this case, you only had new in the original code. You don't want unique_ptr to manage delete
I am trying to create a vector with a class as its template which has a std::thread member. However, I am not sure on how to properly create the initialization list using the thread. What I have currently is this:
class someclass
{
public:
std::thread thread;
int id;
someclass(std::thread init_thread, int init_id) :
thread(&init_thread),
id(init_id)
{}
};
However, when I try to compile it in VS2012, I get the following error:
f:\program files (x86)\microsoft visual studio 11.0\vc\include\functional(1152): error C2064: term does not evaluate to a function taking 0 arguments
which point to the line:
_VARIADIC_EXPAND_0X(_CLASS_BIND, , , , )
If I remove the & from the thread(&init_thread) initialization I get those errors instead:
1>f:\users...\project\source.cpp(43): error C2248: 'std::thread::thread' : cannot access private member declared in class 'std::thread'
1> f:\program files (x86)\microsoft visual studio 11.0\vc\include\thread(73) : see declaration of 'std::thread::thread'
1> f:\program files (x86)\microsoft visual studio 11.0\vc\include\thread(32) : see declaration of 'std::thread'
So, my question is: How would I correctly created such an initialization list?
Later on in the code I doing the following as well (just for reference...)
void function()
{
// ....
std::vector<someclass> v_someclass;
v_someclass.push_back(someclass((std::thread(session, socket)),id));
// ....
}
There are two problems in your code. The most important one is that std::thread is not copy-constructable, but only move-copy constructable. You can make this intent clear by having an rvalue reference as parameter, and you have to use std::move when constructing the thread data member. Second, you should not take the address of the parameter. Your data member is not a pointer.
someclass(std::thread&& init_thread, int init_id) :
thread(std::move(init_thread)),
id(init_id)
This means you can only construct someclass using an std::thread rvalue. For example
someclass sc0(std::thread(args), 42);
std::thread t(args);
someclass sc1(std::move(t), 42);
Edit Note that you can actually have a value parameter: someclass(std::thread, int), but the error message you get when passing an lvalue is not as clear as the one you get with the rvalue reference parameter.
I am just trying to compile a bit bigger project using the Visual Studio 2012 Release Candidate, C++. The project was/is compiled using the VS2010 now. (I am just greedy to get the C++11 things, so I tried. :)
Apart of things that I can explain by myself, the project uses the code like this:
ostringstream ostr;
ostr << "The " __FUNCTION__ "() failed to malloc(" << i << ").";
throw bad_alloc(ostr.str().c_str());
The compiler now complains
error C2248: 'std::bad_alloc::bad_alloc' : cannot access private member declared
in class 'std::bad_alloc'
... which is true. That version of constructor is now private.
What was the reason to make that version of constructor private? Is it recommended by C++11 standard not to use that constructor with the argument?
(I can imagine that if allocation failed, it may cause more problems to try to construct anything new. However, it is only my guess.)
Thanks,
Petr
The C++11 Standard defines bad_alloc as such (18.6.2.1):
class bad_alloc : public exception {
public:
bad_alloc() noexcept;
bad_alloc(const bad_alloc&) noexcept;
bad_alloc& operator=(const bad_alloc&) noexcept;
virtual const char* what() const noexcept;
};
With no constructor that takes a string. A vendor providing such a constructor would make the code using it not portable, as other vendors are not obliged to provide it.
The C++03 standard defines a similar set of constructors, so VS didn't follow this part of the standard even before C++11. MS does try to make VS as standard compliant as possible, so they've probably just used the occasion (new VS, new standard) to fix an incompatibility.
Edit: Now that I've seen VS2012's code, it is also clear why the mentioned constructor is left private, instead of being completely removed: there seems to be only one use of that constructor, in the bad_array_new_length class. So bad_array_new_length is declared a friend in bad_alloc, and can therefore use that private constructor. This dependency could have been avoided if bad_array_new_length just stored the message in the pointer used by what(), but it's not a lot of code anyway.
If you are accustomed to passing a message when you throw a std::bad_alloc, a suitable technique is to define an internal class that derives from std::bad_alloc, and override ‘what’ to supply the appropriate message.
You can make the class public and call the assignment constructor directly, or make a helper function, such as throw_bad_alloc, which takes the parameters (and additional scalar information) and stores them in the internal class.
The message is not formatted until ‘what’ is called. In this way, stack unwinding may have freed some memory so the message can be formatted with the actual reason (memory exhaustion, bad request size, heap corruption, etc.) at the catch site. If formatting fails, simply assign and return a static message.
Trimmed example:
(Tip: The copy constructor can just assign _Message to nullptr, rather than copy the message since the message is formatted on demand. The move constructor, of course can just confiscate it :-).
class internal_bad_alloc: public std::bad_alloc
{
public:
// Default, copy and move constructors....
// Assignment constructor...
explicit internal_bad_alloc(int errno, size_t size, etc...) noexcept:
std::bad_alloc()
{
// Assign data members...
}
virtual ~internal_bad_alloc(void) noexcept
{
// Free _Message data member (if allocated).
}
// Override to format and return the reason:
virtual const char* what(void) const noexcept
{
if (_Message == nullptr)
{
// Format and assign _Message. Assign the default if the
// format fails...
}
return _Message;
}
private:
// Additional scalar data (error code, size, etc.) pass into the
// constructor and used when the message is formatted by 'what'...
mutable char* _Message;
static char _Default[];
}
};
//
// Throw helper(s)...
//
extern void throw_bad_alloc(int errno, size_t size, etc...)
{
throw internal_bad_alloc(errno, size, etc...);
}
I've been using Crypto++ with VS2005 and VS2010 for a while now. But recently I needed to use it with and application directly. The same code compiles fine when I'm compiling as a DLL and does not compile when compiling as an application.
This is the smallest sample that reproduces the error is this (based on cryptopp561\algparam.h:301 CryptoPP::AlgorithmParametersTemplate
class Base
{
protected:
virtual void MoveInto(void *p) const = 0;
};
template<class T>
class Test: public Base
{
public:
void MoveInto(void * buffer) const
{
Test<T> *x = new(buffer) Test<T>(*this);
}
};
extern template class Test<bool>;
The compilation parameters are the same, only difference that I saw was the configuration type in the project ("Application (.exe)" generates the error and "Dynamic Library (.dll)" does not).
This is the compiler error:
main.h(15): error C2061: syntax error : identifier 'buffer'
main.h(14) : while compiling class template member function 'void Test<T>::MoveInto(void *) const'
with
[
T=bool
]
main.h(20) : see reference to class template instantiation 'Test<T>' being compiled
with
[
T=bool
]
It seems to occur only when theres inheritance. Ommiting : public Base in the class Test declaration makes the error go away.
EDIT:
The problem was in a header included somewhere that defined a a debug version for operator new but didn't declared the placement new version.
Did you #include <new>, the header file that declares placement-new?
Funnily, extern templates are to tell the compiler to not instantiante at some point, so the second error does not make sense to me. Are you certain your compiler has support for extern templates? What if you do the opposite, explicit instantiation:
template class Test<bool>;
I am running into a problem when trying to implicitly convert one of my dynamic types. There are two assemblies with definitions similar to the following:
Configuration.dll:
public class ConfigurationValue : DynamicObject
{
public ConfigurationValue(string val)
{
//...
}
//...
public static implicit operator string(ConfigurationValue val)
{
return val.ToString();
}
}
There is another class in this dll called Configuration with a member variable called Instance (to make the class singleton). This variable holds the ConfigurationValue instances in a dictionary and is of type dynamic. This allows me to do this following:
Server.dll:
//...
if (Configuration.Instance.SecurityLevel != "Insecure")
{
//...
}
Assuming that SecurityLevel is in the dictionary.
This if statement appears verbatim in my code and always fails with the following error:
{"Operator '!=' cannot be applied to operands of type 'System.Dynamic.DynamicObject' and 'string'"}
Previously, when these two classes were in the same assembly, this code worked fine. Can anyone tell me what I'm doing wrong here?
Thanks,
Max
Solved the problem, a little embarrassing actually, I forgot to change the container class for ConfigurationValue (e.g. the type of Configuration.Instance) from internal to public when I moved it to the new assembly, so of course the type couldn't be resolved and the implicit conversion was not found
Try
var SecurityLevel = new ConfigurationValue("Insecure");