Я вижу, что я считаю ошибочной / неправильной ошибкой компилятора при использовании компилятора Visual Studio 2010. Я нахожусь в процессе переноса нашей кодовой базы из Visual Studio 2005, и я наткнулся на конструкцию, которая раньше создавалась правильно, но теперь генерирует ошибку компилятора C2248.
Очевидно, что приведенный ниже фрагмент кода был обобщенным, но это скомпилированный пример сценария. Шаблон ObjectPtr<T>
C ++ взят из нашей кодовой базы и является источником рассматриваемой ошибки. Кажется, что происходит, что компилятор генерирует вызов конструктора копирования для ObjectPtr<T>
, когда это не должно происходить (см. Мой блок комментариев в методе SomeContainer::Foo()
ниже). Для этой конструкции кода есть открытый оператор приведения для SomeUsefulData *
в ObjectPtr<SomeUsefulData>
, но он не выбирается внутри выражения true , если оператор ?:
. Вместо этого я получаю две ошибки в приведенной ниже цитате блока.
Исходя из моих знаний C ++, этот код должен компилироваться. Кто-нибудь еще видел такое поведение? Если нет, может кто-нибудь указать мне на разъяснение правил разрешения компилятора, которое объясняет, почему в этом случае он пытается создать копию объекта?
Заранее спасибо,
Дилан Бурк
Вывод сборки Visual Studio:
c: \ projects \ objectptrtest \ objectptrtest.cpp (177): ошибка C2248: 'ObjectPtr :: ObjectPtr': невозможно получить доступ к закрытому члену, объявленному в классе 'ObjectPtr'
с
[T = SomeUsefulData]
c: \ projects \ objectptrtest \ objectptrtest.cpp (25): см. объявление ObjectPtr :: ObjectPtr
с
[T = SomeUsefulData]
c: \ projects \ objectptrtest \ objectptrtest.cpp (177): ошибка C2248: «ObjectPtr :: ObjectPtr»: невозможно получить доступ к закрытому члену, объявленному в классе «ObjectPtr»
с
[T = SomeUsefulData]
c: \ projects \ objectptrtest \ objectptrtest.cpp (25): см. объявление «ObjectPtr :: ObjectPtr»
с
[T = SomeUsefulData]
Ниже приведен минимальный компилируемый пример сценария:
#include <stdio.h>
#include <tchar.h>
template<class T>
class ObjectPtr {
public:
ObjectPtr<T> (T* pObj = NULL, bool bShared = false) :
m_pObject(pObj), m_bObjectShared(bShared)
{}
~ObjectPtr<T> ()
{
Detach();
}
private:
// private, unimplemented copy constructor and assignment operator
// to guarantee that ObjectPtr<T> objects are not copied
ObjectPtr<T> (const ObjectPtr<T>&);
ObjectPtr<T>& operator = (const ObjectPtr<T>&);
public:
T * GetObject ()
{ return m_pObject; }
const T * GetObject () const
{ return m_pObject; }
bool HasObject () const
{ return (GetObject()!=NULL); }
bool IsObjectShared () const
{ return m_bObjectShared; }
void ObjectShared (bool bShared)
{ m_bObjectShared = bShared; }
bool IsNull () const
{ return !HasObject(); }
void Attach (T* pObj, bool bShared = false)
{
Detach();
if (pObj != NULL) {
m_pObject = pObj;
m_bObjectShared = bShared;
}
}
void Detach (T** ppObject = NULL)
{
if (ppObject != NULL) {
*ppObject = m_pObject;
m_pObject = NULL;
m_bObjectShared = false;
}
else {
if (HasObject()) {
if (!IsObjectShared())
delete m_pObject;
m_pObject = NULL;
m_bObjectShared = false;
}
}
}
void Detach (bool bDeleteIfNotShared)
{
if (HasObject()) {
if (bDeleteIfNotShared && !IsObjectShared())
delete m_pObject;
m_pObject = NULL;
m_bObjectShared = false;
}
}
bool IsEqualTo (const T * pOther) const
{ return (GetObject() == pOther); }
public:
T * operator -> ()
{ ASSERT(HasObject()); return m_pObject; }
const T * operator -> () const
{ ASSERT(HasObject()); return m_pObject; }
T & operator * ()
{ ASSERT(HasObject()); return *m_pObject; }
const T & operator * () const
{ ASSERT(HasObject()); return (const C &)(*m_pObject); }
operator T * ()
{ return m_pObject; }
operator const T * () const
{ return m_pObject; }
operator bool() const
{ return (m_pObject!=NULL); }
ObjectPtr<T>& operator = (T * pObj)
{ Attach(pObj, false); return *this; }
bool operator == (const T * pOther) const
{ return IsEqualTo(pOther); }
bool operator == (T * pOther) const
{ return IsEqualTo(pOther); }
bool operator != (const T * pOther) const
{ return !IsEqualTo(pOther); }
bool operator != (T * pOther) const
{ return !IsEqualTo(pOther); }
bool operator == (const ObjectPtr<T>& other) const
{ return IsEqualTo(other.GetObject()); }
bool operator != (const ObjectPtr<T>& other) const
{ return !IsEqualTo(other.GetObject()); }
bool operator == (int pv) const
{ return (pv==NULL)? IsNull() : (LPVOID(m_pObject)==LPVOID(pv)); }
bool operator != (int pv) const
{ return !(*this == pv); }
private:
T * m_pObject;
bool m_bObjectShared;
};
// Some concrete type that holds useful data
class SomeUsefulData {
public:
SomeUsefulData () {}
~SomeUsefulData () {}
};
// Some concrete type that holds a heap-allocated instance of
// SomeUsefulData
class SomeContainer {
public:
SomeContainer (SomeUsefulData* pUsefulData)
{
m_pData = pUsefulData;
}
~SomeContainer ()
{
// nothing to do here
}
public:
bool EvaluateSomeCondition ()
{
// fake condition check to give us an expression
// to use in ?: operator below
return true;
}
SomeUsefulData* Foo ()
{
// this usage of the ?: operator generates a C2248
// error b/c it's attempting to call the copy
// constructor on ObjectPtr<T>
return EvaluateSomeCondition() ? m_pData : NULL;
/**********[ DISCUSSION ]**********
The following equivalent constructs compile
w/out error and behave correctly:
(1) explicit cast to SomeUsefulData* as a comiler hint
return EvaluateSomeCondition() ? (SomeUsefulData *)m_pData : NULL;
(2) if/else instead of ?:
if (EvaluateSomeCondition())
return m_pData;
else
return NULL;
(3) skip the condition check and return m_pData as a
SomeUsefulData* directly
return m_pData;
**********[ END DISCUSSION ]**********/
}
private:
ObjectPtr<SomeUsefulData> m_pData;
};
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}