15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Embedded Arrays

Farhad Sadaghiani -- hadi@interlog.com
Thursday, October 24, 1996

Environment: VC++ 4.0, Windows 95

Hi, how's it going?

  Well, it's not going so good for me.  I'm trying to make a CArray which
has another CArray in it.  Below are the two classes which are the TYPE for
the CArray.

class CFileInfo
{
public:
  CString       strPath;        
  CString	strName;        
  DWORD		dwLength;		
};

class CDirInfo
{
public:
  LPARAM     lParam;      
  CString    strDirName;
  CArray fileArray;
};


I then construct the CArray with no problem.

CArray m_dirInfo;


Now, when it comes to filling the array, I have a problem.  I can add
"fileinfo" to "dirinfo" successfully, but when I go to add "dirinfo" to
"m_dirInfo" I get an error, namely: "error C2558: 'CDirInfo::CDirInfo' : no
copy constructor available".  Below is the code I use to add the arrays.

void CTreeView1::SetupArray(CString name)
{
  CDirInfo dirinfo;
  CFileInfo fileinfo;

  while ( ... )
  {
   ...
   ...
   fileinfo.strPath = "Test_Path";
   fileinfo.strName = "Test_Name";
   fileinfo.dwLength = 0;

   // now add the "fileinfo" array into dirinfo
   dirinfo.fileArray.Add((CFileInfo) fileinfo);    // this is successfull
and works
  }  

  // having exited the loop, it's time to add "dirinfo" (which contains an
array of CFileInfo)
  // to the member variable m_dirInfo.

  m_dirInfo.Add((CDirInfo) dirinfo);

  // the above line causes the error: "error C2558: 'CDirInfo::CDirInfo' :
no copy constructor available".    // Below is the code I use to add the arrays

}

Please help me!

Thanks.







Roger Onslow/Newcastle/Computer Systems Australia/
Monday, October 28, 1996

[Mini-digest: 3 responses]

>class CFileInfo
>{
>public:
>  CString       strPath;        
>  CString strName;        
>  DWORD  dwLength;  
>};
>
>class CDirInfo
>{
>public:
>  LPARAM     lParam;      
>  CString    strDirName;
>  CArray fileArray;

I'd use CArray fileArray;
passing args by reference (2nd param is type function args have) is nicer as no 
unnecessary copy to temporary involved.
In general, if using any sort of struct or class as CArray elements, use a 
reference as second param.

>};
>
>
>I then construct the CArray with no problem.
>
>CArray m_dirInfo;

Same here -- use CDirInfo& for second parameter

>
>
>Now, when it comes to filling the array, I have a problem.  I can add
>"fileinfo" to "dirinfo" successfully, but when I go to add "dirinfo" to
>"m_dirInfo" I get an error, namely: "error C2558: 'CDirInfo::CDirInfo' : no
>copy constructor available".  Below is the code I use to add the arrays.

no copy constructor because of CArray inside your CDirInfo -- compiler doesn't 
know how to do a default copy constructor because CArray doesn;t supply one.  
But this is just a symptom of the problem.

>void CTreeView1::SetupArray(CString name)
>{
>  CDirInfo dirinfo;
>  CFileInfo fileinfo;
>
>  while ( ... )
>  {
>   ...
>   ...
>   fileinfo.strPath = "Test_Path";
>   fileinfo.strName = "Test_Name";
>   fileinfo.dwLength = 0;
>
>   // now add the "fileinfo" array into dirinfo
>   dirinfo.fileArray.Add((CFileInfo) fileinfo);    // this is successfull
>and works

Why cast a CFileInfo to CFileInfo in the above line .. seems redundant.
Casts are dangerous things and should be avoided like the plague unless they 
are actually necessary.
In anycase, you should try to use the static_cast, const_cast and 
reinterpret_cast operators instead of the old fashioned casts, as these new 
operators give more info to the compiler and the reader about WHY the cast is 
there anyway.
>  }  
>
>  // having exited the loop, it's time to add "dirinfo" (which contains an
>array of CFileInfo)
>  // to the member variable m_dirInfo.
>
>  m_dirInfo.Add((CDirInfo) dirinfo);
>

Yes, error because you have not told the compiler hoe to copy.
You should use reference when defining the CArray to avoid the copy here
However, that won't avoid *all* the copy (expensive) copy constructors, just 
the ones you can avoid.

You will need to write your  own copy constructor AND assignment operator for 
CDirInfo which explicitly says how to copy the CArray.
>  // the above line causes the error: "error C2558: 'CDirInfo::CDirInfo' :
>no copy constructor available".    // Below is the code I use to add the arrays
>
>}
>
>Please help me!

Hope I have
>
>Thanks.

You're welcome!!

Roger Onslow
RogerO@compsys.com.au

Homer: "Operator!  Give me the number for 911" (it's mfc-l@netcom.com :-)
-----From: "Alexander(Sasha) Grinshpun" 

The reason for this phenomenon is that no copy constructor was defined
for CDirInfo (that is what compiler said). When this constructor isn't
defined by the user, the compiler tries to generate it for you by
recursively calling copy constructors for base classes and data members
of your class. In your case, it tries to apply copy constructors of
LPARAM, CString and CArray<...>. For LPARAM and CString it works just
fine, but CArray doesn't have user-defined copy constructor and compiler
tries to generate it for you. CArray is derived from CObject that have
private copy constructor (and assignment operator, btw). So compiler
fails to generate copy constructor for this member and, as a consequence
, for CDirInfo as a whole too. This design decision in MFC force you
to explicitly define copy constructors and assignment that is a good
practice anyway. So, all you have to do is to define 
CDirInfo::CDirInfo(const CDirInfo&) method. 

BTW, you can get more effective program by using reference to data as
ARG_TYPE in CArray templates, e.g:
CArray and CArray

Thanks,
Sasha.

-----From: Mark Wright 

Farhad Sadaghiani wrote:
>    // now add the "fileinfo" array into dirinfo
>    dirinfo.fileArray.Add((CFileInfo) fileinfo);    // this is successfull

You don't need to cast fileinfo.

>   // having exited the loop, it's time to add "dirinfo" (which contains an
> array of CFileInfo)
>   // to the member variable m_dirInfo.
> 
>   m_dirInfo.Add((CDirInfo) dirinfo);
> 
>   // the above line causes the error: "error C2558: 'CDirInfo::CDirInfo' :
> no copy constructor available".    // Below is the code I use to add the arrays

Doing an Add(myvariable) requires a copy to take place.  Your program
knows how to copy an LPARAM and a CString (lParam and strDirName), but
it doesn't know how to copy a CArray.  You need to make fileArray an
array with an operator= function.  Create a class like:

class CFileArray : public CArray
{
	CFileArray& operator=( CFileArray& src );
};

And write an operator= function which will copy 'src' into 'this'.

--------------------+---------------------------------------------------
Mark Wright         |   Steven King on the V-chip:                     
(mswright@visi.com) |   "if you want to put one in my remote control,  
                    |    you'll have to pry it from my cold, dead hand." 
--------------------+---------------------------------------------------




| Вернуться в корень Архива |