CDBVariant in CArray

Intrebari legate de programarea cu biblioteci precum MFC, ATL, WTL si GDI+.
mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

CDBVariant in CArray

Post by mesajflaviu » 24 Apr 2012, 19:29

Incerc sa pun elemente CDBVariant intr-un CArray :

Code: Select all

// CMyClass.h
BOOL RetrieveData(LPCTSTR lpszSQL,CArray<CDBVariant,CDBVariant&> arrResult);
// CMyClass.cpp
BOOL RetrieveData(LPCTSTR lpszSQL,CArray<CDBVariant,CDBVariant&> arrResult);
{
    CDBVariant dbVariant;
    // retrieve dbVariant
    arrResult.Add(dbVariant);
}
dar, desi nu am eroare de compilare, cand incerc sa folosesc arrResult, totul crapa (Access violation) ...

As avea 2 intrebari :
  • De ce nu functioneaza aceasta solutie ?
  • Ce alta colectie MFC as putea folosi pentru a putea pune obiecte CDBVariant ? (Ideal ar fi o referinta pentru a o putea-o pune ca paramentru in metoda RetrieveData(...) ).
Multumesc.



Viorel
Microsoft MVP
Microsoft MVP
Posts: 292
Joined: 13 Jul 2007, 12:26

Re: CDBVariant in CArray

Post by Viorel » 24 Apr 2012, 21:07

Varianta prezentată nu prea se compilează în Visual Studio 2010. Dar merge după adăugarea unui “&”:

Code: Select all

BOOL RetrieveData(LPCTSTR lpszSQL,CArray< CDBVariant, CDBVariant & > & arrResult)
Unde anume crapă programul compilat în modul Debug?

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: CDBVariant in CArray

Post by mesajflaviu » 24 Apr 2012, 23:03

Imi cer scuze, copiind codul din alta parte sa il pun aici am uitat sa pun '&' ... codul crapa in momentul cand folosesc RetrieveData(...) :

Code: Select all

    CString sSQL = _T("Select * from mytable");
    CArray<CDBVariant,CDBVariant&> arrItem;        
    RetrieveData(sSQL,arrItem); // <-- Access violation

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDBVariant in CArray

Post by Ovidiu Cucu » 24 Apr 2012, 23:23

Te mai joci cu ODBC? Ai grija ca, CDBVariant e cea mai idioata clasa din tot MFC-ul.
Contine un membru tip pointer la CString (deh, nu se putea baga altfel intr-un union) pe care s-ar putea sa-l pierzi pe drum prin balarii.
Asa ca, daca vrei sa pui date la pastrare, fa-ti mai bine propria clasa sanatoasa. Ca exemplu, am gasit asta prin "arhivele bunicii". :)

Code: Select all

class CDBFValue 
{
   CString m_strVal;
   long m_lVal;
   double m_dVal;
   COleDateTime m_odtVal;

public:
   CDBFValue() : m_lVal(0), m_dVal(0.0) {} 
   CDBFValue(CDBVariant& var);
   virtual ~CDBFValue();
public:
   CString GetString() const {return m_strVal;}
   //...
};

Code: Select all

CDBFValue::CDBFValue(CDBVariant& var) : m_lVal(0), m_dVal(0.0)
{
   switch(var.m_dwType)
   {
   case DBVT_NULL:
      m_strVal.Empty();
      break;
   case DBVT_BOOL:
      m_strVal = var.m_boolVal ? _T("[TRUE]") : _T("[FALSE]");
      break;
   case DBVT_UCHAR:
      m_strVal = var.m_chVal;
      break;
   case DBVT_SHORT:
      m_strVal.Format(_T("%d"), var.m_iVal);
      break;
   case DBVT_LONG:
      m_strVal.Format(_T("%ld"), var.m_lVal);
      break;
   case DBVT_SINGLE:
      m_strVal.Format(_T("%f"), var.m_fltVal);
      break;
   case DBVT_DOUBLE:
      m_strVal.Format(_T("%lf"), var.m_dblVal);
      break;
   case DBVT_DATE:
      {
         COleDateTime odt(var.m_pdate->year, var.m_pdate->month, var.m_pdate->day, 
            var.m_pdate->hour, var.m_pdate->minute, var.m_pdate->second);
         m_strVal = odt.Format();
      }
      break;
   case DBVT_STRING:
      m_strVal = *var.m_pstring;
      break;
   case DBVT_BINARY:
      m_strVal = _T("[BLOB]");
      break;
   default:
      m_strVal.Empty();
   }
} 
Mai departe umbli cu ceva de genul

Code: Select all

typedef CArray<CDBFValue, CDBFValue&> Row;
// ...
CArray<Row*, Row*> m_arrValues;
//...

      Row* pRow = new Row;
      pRow->SetSize(nFieldCount);
      for(short nField = 0; nField < nFieldCount; nField++)
      {
         CDBVariant var;
      
         m_rs.GetFieldValue(nField, var);
         CDBFValue value(var); // <-- mai sanatos asa!
         pRow->SetAt(nField, value);
       }
      m_arrValues.Add(pRow);
Am dat ceva copy/paste-uri la intamplare, sper sa fie cu folos.
Daca vrei, iti dau tot programelul, dar trebuie mai intai sa-l sterg putin de praf. ;)

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: CDBVariant in CArray

Post by mesajflaviu » 25 Apr 2012, 08:55

Daca vrei, iti dau tot programelul, dar trebuie mai intai sa-l sterg putin de praf.
Cum sa nu, e bun si nesters ...

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDBVariant in CArray

Post by Ovidiu Cucu » 25 Apr 2012, 14:02

mesajflaviu wrote:
Daca vrei, iti dau tot programelul, dar trebuie mai intai sa-l sterg putin de praf.
Cum sa nu, e bun si nesters ...
Programelul nu e numai prafuit, dar e facut la repezeala si contine chestii batute-n cuie si/sau incomplete.

In fine poti sa iei din el o idee cam cum faci sa pui la pastrare CDBVariant-uri.
Cum spuneam, CDBVariant contine un membru tip CString* (si inca alti doi pe acelasi calapod).
Constructor de copiere explicit / operator de atribuire supraincarcat nu are, asa ca se face copiere implicita, membru cu membru.
Daca are membri pointeri se copie, normal, pointeri. Pana aici, toate bune, frumoase, super-small si super-fast.
Dar in momentul cand de exemplu inchizi recordset-ul, mai mult ca sigur pointerasii arata catre Muma Bitilor din Padure, iar daca te iei de ei, faci buba. :)

Asa ca, mai bine iti faci tu o clasa/structura mai sanatoasa in care sa pui rezultatul la pastrare. Un exemplu este cel din postul anterior si din programelul pe care-l pun aici.
Mai poti lua de acolo o idee cam cum se poate lucra cu LVN_GETDISPINFO si LVN_ODCACHEHINT.
Repet insa, tot ce-i acolo e facut la repezeala asa ca se poate si mai bine.
Oricum, daca sunt nelamuriri, fell free to ask. ;)
DBFQuery.zip
(22.44 KiB) Downloaded 250 times

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: CDBVariant in CArray

Post by mesajflaviu » 25 Apr 2012, 15:07

Multumesc pentru exemplu, o sa-l rasfoiesc acum ... intradevar, eu inchid recordset-ul si incerc sa lucrez cu membrii CDBVariant ... cred ca acolo e problema ... am mai incercat sa aduc CDBVariant inntr-un CTypedPtrArray :

Code: Select all

// MyClass.h
virtual BOOL RetrieveData(LPCTSTR lpszSQL,CTypedPtrArray<CPtrArray,CDBVariant*>& arrResult)
// MyClass.cpp
BOOL CMyClass::RetrieveData(LPCTSTR lpszSQL,CTypedPtrArray<CPtrArray,CDBVariant*>& arrResult)
{
	CDBVariant* pDBVariant;
	nFieldCount = pRs->GetODBCFieldCount();

	while(! pRs->IsEOF())
	{
		for(UINT i = 0;i < nFieldCount;++i)
		{
			try
			{
				pDBVariant = new CDBVariant;
				pRs->GetFieldValue(i,*pDBVariant);
			}
			catch(..){}
			arrResult.Add(pDBVariant);
		}
		pRs->MoveNext();
	}

Code: Select all

	CString sSQL;
	CTypedPtrArray<CPtrArray,CDBVariant*> arrItem;
	CMyClass::RetrieveData(sSQL,arrItem);
	while(arrItem.GetSize())
	{
		CDBVariant* pTemp = arrItem.GetAt(0);
                                // do whatever with pTemp ...
		delete pTemp;
		arrItem.RemoveAt(0);
	}
 
singura chestie ar fi ca user-ul trebuie sa fie atent sa stearga pointerii la CDBVariant ... altfel iese urat ...

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDBVariant in CArray

Post by Ovidiu Cucu » 25 Apr 2012, 15:37

mesajflaviu wrote: ... am mai incercat sa aduc CDBVariant inntr-un CTypedPtrArray
Incercarea moarte n-are. Insa poti sa-l bagi si-n CArray si-n CTypedPtrArray si in CMamaLuiArray ca tot aia-i. :biggrin: Ce-am spus mai sus ramane valabil.

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: CDBVariant in CArray

Post by mesajflaviu » 25 Apr 2012, 16:31

Ovidiu Cucu wrote:Incercarea moarte n-are.
Da' incercatoru are :(

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: CDBVariant in CArray

Post by mesajflaviu » 25 Apr 2012, 16:33

mesajflaviu wrote:Imi cer scuze, copiind codul din alta parte sa il pun aici am uitat sa pun '&' ... codul crapa in momentul cand folosesc RetrieveData(...) :

Code: Select all

    CString sSQL = _T("Select * from mytable");
    CArray<CDBVariant,CDBVariant&> arrItem;        
    RetrieveData(sSQL,arrItem); // <-- Access violation
Viorel, am vrut sa spun ca desi in metoda RetrieveData nu am nici o problema (mers cu debuggeru pas cu pas), cand incerc sa o folosesc, la iesirea din metoda, am 'Access violation' ...

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDBVariant in CArray

Post by Ovidiu Cucu » 26 Apr 2012, 19:31

Un mic quiz de C++/MFC, legat oarecum de ce discutam aici.
Fie clasele

Code: Select all

struct CFoo
{
   CString* m_pstring;
};

Code: Select all

struct CBar
{
   CString m_string;
};
Este mai buna clasa CFoo decat clasa CBar din punct de vedere al performantei?
Daca da, de ce?

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: CDBVariant in CArray

Post by mesajflaviu » 26 Apr 2012, 22:03

Poate spun vreo gogmanie, dar si calcand prin strachini pot ajunge mai departe :
Pai CFoo "tine" doar adresa membrului m_pstring, pe cand CBar are chiar locatia m_string, care poate fi cat zidu' chinezesc ... cand e vorba de accesat membrul uneia dintre cele doua clase, accesul la m_pstring e mult mai rapid ...

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: CDBVariant in CArray

Post by Ovidiu Cucu » 27 Apr 2012, 09:26

Ceva-ceva mai rapid o fi insa in general la stringuri lungimea/memoria ocupata (care da, poate fi cat zidu' chinezesc) este cea care ne doare in primul rand.
Deci sa vedem! Incearcam asta:

Code: Select all

   CString str = _T("Lung cat zidu' chinezesc...");

   CFoo foo;
   CBar bar;
   foo.m_pstring = &str;
   bar.m_string = *foo.m_pstring + "...plus zidu' Berlinului.";

   ASSERT(sizeof(foo) == sizeof(bar));
Zice ceva? Nu zice, si nu din cauza ca s-au apucat unii si l-au daramat pe ala din Berlin (eh, cred ca o bucatica de samanta tot au lasat) :).
Cele doua size-uri sunt egale pentru ca, CString contine un singur membru (LPTSTR m_pchData) care e tot un pointeras, deci sizeof(CString*) == sizeof(CString), sizeof(foo.m_pstring) == sizeof(bar.m_string) si in fine sizeof(foo) == sizeof(bar). Se mai poate discuta aici, insa deocamdata nu intru in amanunte.

Deci pana acum nu pare sa fi obtinut o crestere de performanta in ceea ce priveste size-ul.
Sa incercam alfel:

Code: Select all

   CString str = _T("Lung cat zidu' chinezesc...");
   str += _T("...plus zidu' Berlinului.");

   CFoo foo1;
   CBar bar1;
   foo1.m_pstring = &str;
   bar1.m_string = str;

   CFoo foo2 = foo1; // #1
   CBar bar2 = bar1; // #2
In liniile marcate cu #1 si #2 se face copiere.
Q: Este mai optima copierea in linia #1 datorita faptului ca, CFoo contine pointer la CString si nu obiect tip CString? De ce?

// Nu-i nici o suparare/rusine daca iese-un porumbel. In cele din urma este legata de OP iar dupa aceea putem sa-i trimtem problema si lui nenea Adam.
Adam Savage (MythBusters).jpg
Adam Savage (MythBusters).jpg (14.65 KiB) Viewed 7057 times
Sa vedem, el ce parere-si da... :D

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: CDBVariant in CArray

Post by mesajflaviu » 27 Apr 2012, 10:37

Pai la fel, foo2 cu al sau foo2.m_pstring contine doar adresa stringului str, pe cand bar2 are in bar2.m_string chiar obiectul str cu tot zidu' ....

nedo
Junior
Junior
Posts: 32
Joined: 14 Oct 2011, 20:18
Judet: Bucureşti

Re: CDBVariant in CArray

Post by nedo » 27 Apr 2012, 10:42

Daca nu ma insel, aici ar trebui sa fie cam la fel de rapide. O clasa care nu are un membru de copiere va avea atribuit de catre compilator unul, care va face un shalow copy, va copia doar adresele membrilor si le va atribui noilor membri.
Mai pe romaneste:
fool.&m_pstring = foo2.&m_pstring;
si barl.&m_string = bar2.&m_string;

Post Reply