|
There is no way to make data completely unrecoverable. But using some shredding algorithms you can slow down the process of recovery of the shredded(deleted) data.
|
|
|
|
|
The following question is about how to handle assignment operators (& copy constructors)
in a hierarchy of polymorphic objects in order to be able to work with all kind of assignments & copy:
i.e. we would ideally like to work always with base class pointers, but also allow to use
directly derived class pointers.
In fact I do present two techniques to deal with this argument:
A) The first does make use of "virtual" assignment operators
and, as far as I know, should be the "standard" way to deal with this argument in C++,
but it has the drawback that as soon as your hierarchy is more than one level deep
it leads to a combinatorial explosion of assignment operators.
This technique I call "Polymorphism A" in the following.
B) The second technique does make use of an aux virtual copy method,
using this aux virtual copy method fewer assignment operators have to be defined,
but it has the drawback that you cannot call directly the base class assignment op. from derived ones.
This technique I call "Polymorphism B" in the following.
My question is more like an open discussion: i.e. I do ask what are your opinions on both techniques,
what drawbacks you may see in them, and, eventually, if you do know of a better way to solve the same problem.
In the sample code I give objects are relatively simple, but keep in mind that we would like
to apply those techniques to complicated objects where "deep" copies are to be used.
Let us see the code:
------- Polymorphism A - hierarchy --------------------
#include "stdafx.h"
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
using namespace std;
class CBase {
private:
CBase() { cout << "CBase() default ctor called" << endl;
_data = -1; _isvalid = false; };
public:
explicit CBase(const int data) { cout << "CBase(const int data) explicit ctor called" << endl;
_data = data; _isvalid = true; };
virtual ~CBase() { cout << "~CBase() dtor called" << endl; };
public:
CBase(const CBase& iOther) { cout << "CBase(const CBase& iOther) copy ctor called" << endl;
copyBase(iOther); };
virtual CBase& operator=(const CBase& iOther) { cout << "CBase& CBase::operator=(const CBase& iOther) assignment called" << endl;
if( this != &iOther ) {
copyBase(iOther); }
return *this;
};
private:
void copyBase(const CBase& iOther)
{ cout << "CBase::copyBase() copy called" << endl;
_data = iOther._data; _isvalid = iOther._isvalid; };
public: int getData() const { return _data; };
void setData(const int data) { _data = data; };
bool isValid() const { return _isvalid; };
void setValid(const bool isvalid) { _isvalid = isvalid; };
private:
int _data; bool _isvalid; };
class CDerivedA : public CBase {
private:
CDerivedA() : CBase((int) -1)
{ cout << "CDerivedA() default ctor called" << endl;
_dataA = -1.0; setValid(false); };
public:
explicit CDerivedA(const double dataA) : CBase((int) 0) { cout << "CDerivedA(const double dataA) explicit ctor called" << endl;
_dataA = dataA; };
virtual ~CDerivedA() { cout << "~CDerivedA() dtor called" << endl; };
public:
CDerivedA(const CDerivedA& iOther) : CBase(iOther) { cout << "CDerivedA(const CDerivedA& iOther) copy ctor called" << endl;
_dataA = iOther._dataA; };
virtual CDerivedA& operator=(const CDerivedA& iOther) { cout << "CDerivedA& CDerivedA::operator=(const CDerivedA& iOther) assignment called" << endl;
if( this != &iOther ) {
this->CBase::operator=(iOther);
_dataA = iOther._dataA; }
return *this;
};
CDerivedA(const CBase& iOther)
: CBase(iOther) { cout << "CDerivedA(const CBase& iOther) copy ctor called" << endl;
buildVirtualCopy(iOther);
};
virtual CBase& operator=(const CBase& iOther) { cout << "CBase& CDerivedA::operator=(const CBase& iOther) assignment called" << endl;
if( this != &iOther ) {
this->CBase::operator=(iOther);
buildVirtualCopy(iOther);
}
return *this;
};
private:
void buildVirtualCopy(const CBase& iOther)
{
cout << "CDerivedA::buildVirtualCopy copy ctor called" << endl;
const CDerivedA* pOther = dynamic_cast<const CDerivedA*> (&iOther);
if ( nullptr != pOther ) {
_dataA = pOther->_dataA;
}
else {
cout << "CDerivedA: explicit conversion from other type is forbidden" << endl;
setValid(false); }
};
public: double getDataA() const { return _dataA; };
void setDataA(const double dataA) { _dataA = dataA; };
private:
double _dataA; };
class CDerivedB : public CBase {
private:
CDerivedB() : CBase((int) -1)
{ cout << "CDerivedB() default ctor called" << endl;
_dataB = ""; setValid(false); };
public:
explicit CDerivedB(const string dataB) : CBase((int) 1) { cout << "CDerivedB(const string dataB) explicit ctor called" << endl;
_dataB = dataB; };
virtual ~CDerivedB() { cout << "~CDerivedB() dtor called" << endl; };
public:
CDerivedB(const CDerivedB& iOther) : CBase(iOther) { cout << "CDerivedB(const CDerivedB& iOther) copy ctor called" << endl;
_dataB = iOther._dataB; };
virtual CDerivedB& operator=(const CDerivedB& iOther) { cout << "CDerivedB& CDerivedB::operator=(const CDerivedB& iOther) assignment called" << endl;
if( this != &iOther ) {
this->CBase::operator=(iOther);
_dataB = iOther._dataB; }
return *this;
};
CDerivedB(const CBase& iOther)
: CBase(iOther) { cout << "CDerivedB(const CBase& iOther) copy ctor called" << endl;
buildVirtualCopy(iOther);
};
virtual CBase& operator=(const CBase& iOther) { cout << "CBase& CDerivedB::operator=(const CBase& iOther) assignment called" << endl;
if( this != &iOther ) {
this->CBase::operator=(iOther);
buildVirtualCopy(iOther);
}
return *this;
};
private:
void buildVirtualCopy(const CBase& iOther)
{
cout << "CDerivedB::buildVirtualCopy copy ctor called" << endl;
const CDerivedB* pOther = dynamic_cast<const CDerivedB*> (&iOther);
if ( nullptr != pOther ) {
_dataB = pOther->_dataB;
}
else {
const CDerivedA* pOtherA = dynamic_cast<const CDerivedA*> (&iOther);
if ( nullptr != pOtherA ) {
stringstream ss;
ss << setw(4) << pOtherA->getDataA();
_dataB = ss.str();
cout << "CDerivedB: explicit conversion from CDerivedA type" << endl;
}
else {
setValid(false); }
}
};
public: string getDataB() const { return _dataB; };
void setDataB(const string& dataB) { _dataB = dataB; };
private:
string _dataB; };
------- Polymorphism A - hierarchy --------------------
------- Polymorphism B - hierarchy --------------------
#include "stdafx.h"
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
using namespace std;
class CBase {
private:
CBase() { cout << "CBase() default ctor called" << endl;
_data = -1; _isvalid = false; };
public:
explicit CBase(const int data) { cout << "CBase(const int data) explicit ctor called" << endl;
_data = data; _isvalid = true; };
virtual ~CBase() { cout << "~CBase() dtor called" << endl; };
public:
CBase(const CBase& iOther) { cout << "CBase(const CBase& iOther) copy ctor called" << endl;
copyBase(iOther); };
CBase& operator=(const CBase& iOther) { cout << "CBase& CBase::operator=(const CBase& iOther) assignment called" << endl;
if( this != &iOther ) {
copyBase(iOther); buildVirtualCopy(iOther); }
return *this;
};
private:
void copyBase(const CBase& iOther)
{ cout << "CBase::copyBase() copy called" << endl;
_data = iOther._data; _isvalid = iOther._isvalid; };
protected:
virtual void buildVirtualCopy(const CBase& iOther) { cout << "CBase::buildVirtualCopy copy ctor called, it does nothing" << endl; };
public: int getData() const { return _data; };
void setData(const int data) { _data = data; };
bool isValid() const { return _isvalid; };
void setValid(const bool isvalid) { _isvalid = isvalid; };
private:
int _data; bool _isvalid; };
class CDerivedA : public CBase {
private:
CDerivedA() : CBase((int) -1)
{ cout << "CDerivedA() default ctor called" << endl;
_dataA = -1.0; setValid(false); };
public:
explicit CDerivedA(const double dataA) : CBase((int) 0) { cout << "CDerivedA(const double dataA) explicit ctor called" << endl;
_dataA = dataA; };
virtual ~CDerivedA() { cout << "~CDerivedA() dtor called" << endl; };
public:
CDerivedA(const CDerivedA& iOther) : CBase(iOther) { cout << "CDerivedA(const CDerivedA& iOther) copy ctor called" << endl;
_dataA = iOther._dataA; };
CDerivedA& operator=(const CDerivedA& iOther)
{ cout << "CDerivedA& CDerivedA::operator=(const CDerivedA& iOther) assignment called" << endl;
if( this != &iOther ) {
this->CBase::CBase(iOther); _dataA = iOther._dataA; }
return *this;
};
CDerivedA(const CBase& iOther)
: CBase(iOther) { cout << "CDerivedA(const CBase& iOther) copy ctor called" << endl;
buildVirtualCopy(iOther);
};
protected:
virtual void buildVirtualCopy(const CBase& iOther)
{
cout << "CDerivedA::buildVirtualCopy copy ctor called" << endl;
const CDerivedA* pOther = dynamic_cast<const CDerivedA*> (&iOther);
if ( nullptr != pOther ) {
_dataA = pOther->_dataA;
}
else {
cout << "CDerivedA: explicit conversion from other type is forbidden" << endl;
setValid(false); }
};
public: double getDataA() const { return _dataA; };
void setDataA(const double dataA) { _dataA = dataA; };
private:
double _dataA; };
class CDerivedB : public CBase {
private:
CDerivedB() : CBase((int) -1)
{ cout << "CDerivedB() default ctor called" << endl;
_dataB = ""; setValid(false); };
public:
explicit CDerivedB(const string dataB) : CBase((int) 1) { cout << "CDerivedB(const string dataB) explicit ctor called" << endl;
_dataB = dataB; };
virtual ~CDerivedB() { cout << "~CDerivedB() dtor called" << endl; };
public:
CDerivedB(const CDerivedB& iOther) : CBase(iOther) { cout << "CDerivedB(const CDerivedB& iOther) copy ctor called" << endl;
_dataB = iOther._dataB; };
CDerivedB& operator=(const CDerivedB& iOther)
{ cout << "CDerivedB& CDerivedB::operator=(const CDerivedB& iOther) assignment called" << endl;
if( this != &iOther ) {
this->CBase::CBase(iOther); _dataB = iOther._dataB; }
return *this;
};
CDerivedB(const CBase& iOther) : CBase(iOther) { cout << "CDerivedB(const CBase& iOther) copy ctor called" << endl;
buildVirtualCopy(iOther);
};
protected:
virtual void buildVirtualCopy(const CBase& iOther)
{
cout << "CDerivedB::buildVirtualCopy copy ctor called" << endl;
const CDerivedB* pOther = dynamic_cast<const CDerivedB*> (&iOther);
if ( nullptr != pOther ) {
_dataB = pOther->_dataB;
}
else {
const CDerivedA* pOtherA = dynamic_cast<const CDerivedA*> (&iOther);
if ( nullptr != pOtherA ) {
stringstream ss;
ss << setw(4) << pOtherA->getDataA();
_dataB = ss.str();
cout << "CDerivedB: explicit conversion from CDerivedA type" << endl;
}
else {
setValid(false); }
}
};
public: string getDataB() const { return _dataB; };
void setDataB(const string& dataB) { _dataB = dataB; };
private:
string _dataB; };
------- Polymorphism B - hierarchy --------------------
and a simple test program to test both of them:
------- test program for both hierarchies -------------
int _tmain(int argc, _TCHAR* argv[])
{
cout << "Program starts..." << endl;
cout << endl;
{
CDerivedA* pA0 = new CDerivedA((double) 1.0);
CDerivedA* pA1 = new CDerivedA((double) 2.0);
CDerivedB* pB0 = new CDerivedB(string("This is B1"));
CDerivedB* pB1 = new CDerivedB(string("This is B2"));
cout << endl;
CBase* p00 = nullptr;
CBase* p01 = nullptr;
cout << "Assignment via base pointers of type A objects" << endl;
p00 = pA0;
p01 = pA1;
*p00 = *p01;
cout << "pA0 dataA = " << pA0->getDataA() << endl;
cout << "pA1 dataA = " << pA1->getDataA() << endl;
cout << endl;
p00 = nullptr;
p01 = nullptr;
cout << "Assignment via base pointers of type B objects" << endl;
p00 = pB0;
p01 = pB1;
*p00 = *p01;
cout << "pB0 dataB = " << pB0->getDataB() << endl;
cout << "pB1 dataB = " << pB1->getDataB() << endl;
cout << endl;
p00 = nullptr;
p01 = nullptr;
cout << "Cross Assignment via base pointers from type B objects to type A is forbidden" << endl;
p00 = pA0;
p01 = pB0;
cout << "p00 is pointing to pA0 " << endl;
*p00 = *p01;
cout << "p00 is valid = " << p00->isValid() << endl;
cout << endl;
p00 = nullptr;
p01 = nullptr;
cout << "Cross Assignment via base pointers from type A objects to type B" << endl;
cout << "is allowed by custom conversion... " << endl;
p00 = pB1;
p01 = pA1;
cout << "p00 is pointing to pB1 " << endl;
*p00 = *p01;
cout << "p00 is valid = " << p00->isValid() << endl;
cout << "p00 --> pB1 dataB = " << pB1->getDataB() << endl;
cout << endl;
p00 = nullptr;
p01 = nullptr;
delete pA0;
delete pA1;
delete pB0;
delete pB1;
cout << endl;
}
{
CDerivedA* pA0 = new CDerivedA((double) 1.0);
CDerivedA* pA1 = new CDerivedA((double) 2.0);
CDerivedB* pB0 = new CDerivedB(string("This is B1"));
CDerivedB* pB1 = new CDerivedB(string("This is B2"));
cout << endl;
cout << "Assignment via pointers of type A objects" << endl;
*pA0 = *pA1;
cout << "pA0 dataA = " << pA0->getDataA() << endl;
cout << "pA1 dataA = " << pA1->getDataA() << endl;
cout << endl;
cout << "Assignment via pointers of type B objects" << endl;
*pB0 = *pB1;
cout << "pB0 dataB = " << pB0->getDataB() << endl;
cout << "pB1 dataB = " << pB1->getDataB() << endl;
cout << endl;
delete pA0;
delete pA1;
delete pB0;
delete pB1;
cout << endl;
}
{
cout << "Base class Assignment just works." << endl;
CBase* p00 = nullptr;
CBase* p01 = nullptr;
p00 = new CBase((int) 10);
p01 = new CBase((int) 11);
*p00 = *p01;
cout << "p00 is valid = " << p00->isValid() << endl;
cout << "p00 data = " << p00->getData() << endl;
cout << "p01 is valid = " << p01->isValid() << endl;
cout << "p01 data = " << p01->getData() << endl;
cout << endl;
delete p00;
cout << endl;
cout << "Base class copy ctor just works." << endl;
p00 = new CBase(*p01);
cout << "p00 is valid = " << p00->isValid() << endl;
cout << "p00 data = " << p00->getData() << endl;
delete p00;
delete p01;
cout << endl;
}
{
cout << "Copy ctor via pointers of type A objects" << endl;
CDerivedA* pA1 = new CDerivedA((double) 2.0);
cout << endl;
CDerivedA* pA2 = new CDerivedA(*pA1);
cout << "pA1 dataA = " << pA1->getDataA() << endl;
cout << "pA2 dataA = " << pA2->getDataA() << endl;
delete pA1;
delete pA2;
cout << endl;
cout << "Copy ctor via pointers of type B objects" << endl;
CDerivedB* pB1 = new CDerivedB(string("This is B2"));
cout << endl;
CDerivedB* pB2 = new CDerivedB(*pB1);
cout << "pB1 dataB = " << pB1->getDataB() << endl;
cout << "pB2 dataB = " << pB2->getDataB() << endl;
delete pB1;
delete pB2;
cout << endl;
cout << "Copy ctor via base pointers of type A,B objects" << endl;
CBase* p00 = new CDerivedA((double) 1.0);
CBase* p01 = new CDerivedB(string("This is B1"));
cout << endl;
cout << "A from A via base" << endl;
CDerivedA* pA3 = new CDerivedA(*p00);
cout << endl;
cout << "base from A (slicing)" << endl;
CBase* pA4 = new CBase(*p00); cout << endl;
cout << "B from B via base" << endl;
CDerivedB* pB3 = new CDerivedB(*p01);
cout << endl;
cout << "base from B (slicing)" << endl;
CBase* pB4 = new CBase(*p01); cout << endl;
cout << "A from B via base" << endl;
CDerivedA* pA5 = new CDerivedA(*p01);
cout << endl;
cout << "B from A via base" << endl;
CDerivedB* pB5 = new CDerivedB(*p00);
cout << endl;
delete pA3;
delete pA4;
delete pA5;
delete pB3;
delete pB4;
delete pB5;
delete p00;
delete p01;
cout << endl;
}
int k = getchar();
return 0;
}
------- test program for both hierarchies -------------
Thanks in advance for any suggestion about why you would go with one instead of the other
(or, if eventually you do know a better idiomatic solution).
Federico
|
|
|
|
|
That looks like a shed load of code just to implement copying and assignment. Are you sure that copying objects of arbitrary types is both necessary to your design and won't turn into a complete millstone around your development team's neck? They might not thank you when they have to grind that lot out again to implement a new class? I'm also wincing at how the assignment operators are written - the canonical way you write an assignment operator in C++ is to use a copy and swap.
So... What would I suggest? Firstly go back to your design and see if it can be reworked to use a set of relatively simple principles:
- value types have no polymorphic behaviour and are copy constructable and assignable if appropriate. Use copy and swap to write the assignment operator for a value type
- polymorphic types are accessed through interfaces. Don't assign or copy the objects themselves, reference them through pointers or references to the interfaces they implement. The only place that knows the concrete type of a polymorphic type is the lump of code that creates the object
- don't use implementation inheritance. Containment gives far less headaches
- minimise manual memory management wherever possible. Use parameterise from above (PFA) and objects created on the stack wherever possible. If you write a delete statement pinch yourself and look at using std::unique_ptr or std::shared_ptr instead. RAII is your friend
- make everything exception safe but don't handle exceptions in too many places. One try/catch set in a function
If there's still a need to deep copy objects through pointers to arbitrary base classes then consider implementing a clonable interface. Never slice objects - once you lop off the context you can never get it back.
|
|
|
|
|
Thanks Aescleal,
all the techniques you suggest are fine, but my point was more on the discussion
of the copy ctor and assignment op. themselves: it is clear that if I make them
private, or if I just use the compiler generated ones for POD types, there will
be no worry.
By the way what do you mean exactly by "copy and swap" ? Do you mean this ? :
Object& operator = (const Object& other)
{
Object(other).swap(*this);
return *this;
}
(How do you ensure no self assignment in this case ?, by forwarding to std::swap ?)
My point anyway was about how to do in the correct way when I've a hierarchy,
I've deep copies, I've to be able to use base class pointers or derived pointers:
i.e. in the most general case.
In this general case it seems to me that you're forced to use one of the given approaches,
and that you shall handle all cases of copy ctor and assignment ops explicitly
(derived from derived, derived from base, base from derived, base from base)
maybe just disallowing some of them.
Just to be clear, my point is the following:
CBase* pbase0 = new CDerived(...);
CBase* pbase1 = new CDerived(...);
*pbase0 = *pbase1
Bye
Federico
modified 22-Oct-13 4:44am.
|
|
|
|
|
Generally: Deep hierarchies (i.e. anything more than inheriting an interface) are bad news. Implementation inheritance is the strongest coupling there is and you'll end up with fragile logical designs (you'll spend ages trying to work out what goes where in your class taxonomy and find you have to shuffle a lot of members around) and long build times (when you shuffle you'll have to rebuild the world). If you stick to parameterise from above and interface inheritance you won't have to copy objects, just references and the whole question becomes moot.
Copy and swap is:
T &T::operator=( const T &t )
{
T temp( t );
swap( temp );
return *this;
}
where swap is non-throwing. You get exception safety for free and if you use the PIMPL idiom and lean on std::unique_ptr it's pretty trivial to implement.
|
|
|
|
|
Hello Aesclal,
thanks again, may I ask you (if you got the time) to append some links
in order to let other readers as well understand the topic ?
(e.g. spelling out what is PFA - parameterise from above - and its coupling with interface
inheritance, why you will then work only with references, etc...).
The best would be a link to a public domain example...
About "swap", I left it out first from my discussion in order to focus only on copy ctor
& assignment operators, otherwise you should add also the swap method to the examples.
Anyway, usually I would add this to the assignment op:
T &T::operator=( const T &t )
{
if ( this != &t ) {
T temp( t );
swap( temp );
}
return *this;
}
The PIMPL idiom (for the sake of other readers) is the private implementation idiom.
Bye
Federico
|
|
|
|
|
HI,
I am using SQLFetchScroll for bulk reading from DB .But it is failing for some tables loading where columns contain NULL values.
Can anyone help me on this to get rid of this?
Regards,
ASH
asdsa
|
|
|
|
|
Have you checked the return value to see how it's different from when it succeeds?
Have you seen the diagnostics information provided in the documentation page[^]?
"Real men drive manual transmission" - Rajesh.
|
|
|
|
|
Yes, Rajesh I have checked the return code is -11072.. I am not able to find any related document for this error code
Any help is appreciate..
Thanks,
Ashish
asdsa
|
|
|
|
|
I'd probably try switch ing the return value to one of the values documented.
The possible return values documented are: SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA, SQL_STILL_EXECUTING, SQL_ERROR, SQL_INVALID_HANDLE.
Or you could look up the definitions of these return values to see if any of these are defined as -11072.
"Real men drive manual transmission" - Rajesh.
|
|
|
|
|
Showing a relevant piece of code here might make things easier too.
"Real men drive manual transmission" - Rajesh.
|
|
|
|
|
// NumRowsFetched.
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, sizeof(ORDERINFO), 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, ROW_ARRAY_SIZE, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROWS_FETCHED_PTR, &NumRowsFetched, 0);
// Bind elements of the first structure in the array to the OrderID,
// SalesPerson, and Status columns.
SQLBindCol(hstmt, 1, SQL_C_ULONG, &OrderInfoArray[0].OrderID, 0, &OrderInfoArray[0].OrderIDInd);
SQLBindCol(hstmt, 2, SQL_C_CHAR, OrderInfoArray[0].SalesPerson,
sizeof(OrderInfoArray[0].SalesPerson),
&OrderInfoArray[0].SalesPersonLenOrInd);
SQLBindCol(hstmt, 3, SQL_C_CHAR, OrderInfoArray[0].Status,
sizeof(OrderInfoArray[0].Status), &OrderInfoArray[0].StatusLenOrInd);
// Execute a statement to retrieve rows from the Orders table.
SQLExecDirect(hstmt, "SELECT OrderID, SalesPerson, Status FROM Orders", SQL_NTS);
// Fetch up to the rowset size number of rows at a time. Print the actual
// number of rows fetched; this number is returned in NumRowsFetched.
// Check the row status array to print only those rows successfully
// fetched. Code to check if rc equals SQL_SUCCESS_WITH_INFO or
// SQL_ERRORnot shown.
while ((rc = SQLFetchScroll(hstmt,SQL_FETCH_NEXT,0)) != SQL_NO_DATA) {
asdsa
|
|
|
|
|
So, you've pasted here some code from MSDN[^].
If you're trying that sample mentioned in MSDN, do you have a replica of that database on your DB server?
How many iterations does the loop run, and what is the value that the call returns each time? And if it's that integer value you mentioned earlier, have you tried looking up the header files to see which valid return type is defined as that number? Please try this, and tell me what you find.
And in case you just pasted some random code from MSDN here in the hope that I'll setup a database here and do all the work to figure out what things could go wrong, ... I really don't have to be doing this at 3AM, you know?
"Real men drive manual transmission" - Rajesh.
|
|
|
|
|
Hey there,
I have a function called,
App 1:
void GetImage(CImage * img)
{
//Pass &img over socket to another app
}
App 2:
void DisplayImage()
{
CImage * pImg = &img;
}
Is it possible to pass a class pointer as memory buffer across the socket?
The above code is just an example. My question in general is, whether it's possible to pass any Classes pointer as a memory buffer across sockets.
UPDATE:
This is within same process. In that case can i simply pass the pointer over socket?
Another catch here is, i need to encode all the data in a XML format before sending across the socket.
C++ Code:
CImage *pImage; //pImage hold the data
Inside XML:
<param />&pImage
Can i do like this?
Thanks
modified 15-Oct-13 12:48pm.
|
|
|
|
|
Don Guy wrote: My question in general is, whether it's possible to pass any Classes pointer as
a memory buffer across sockets
That depends. Are you passing it between different processes? If so, then the pointer will have no meaning in the context of the receiving process.
Remember that each process has its own allocation of memory that is separate from every other process. Therefore a memory pointer has no meaning outside its own process.
However, you could send the object itself through a process of serialization: http://msdn.microsoft.com/en-us/library/6bz744w8.aspx[^]
The difficult we do right away...
...the impossible takes slightly longer.
modified 14-Oct-13 20:49pm.
|
|
|
|
|
This is the good solution but "serialization" is usually a blurry word for beginners, I try to give OP a bit of help about serialization. Serialization is the process of converting one or more objects into a self contained piece of data that is self-contained/independent of the volatile state of your program. You do serialization for example when you save out a document into a file. The document data is self-contained and independent of the volatile state of your program because you can perfectly load it back to your program even after a program restart (that causes total loss of volatile state info). When you serialize you don't necessarily have to save the data into a file, instead you can send it over the network to another process that can "load" (deserialize) this data by creating objects that contain the same information from which the serialized data was created in the first process. Of course the pointerss to the objects will be probably different but the connection between the objects and their state variables can be identical.
|
|
|
|
|
Don Guy wrote: Is it possible to pass a class pointer as memory buffer across the socket?
Of course you can. But your application will crash, acchieve nothing and be completely useless.
You can pass the entire class if you want, and all referenced memory. And the other end must know about that class, and all the funcitons is contains.
|
|
|
|
|
Socket is just an unstructured byte stream, so you can certainly pass the pointer address as bytes on to other end. You will have to marshal pointer into bytes @ sending end and unmarshal it back to pointer at receiving end. To unmarshal, the receiver must either share the same address space as the sender or be provided a proxy to the same address space.
Oh, does this start to sound like Remoting?
Yep, that is what this is. Remoting does provide means to make a process function pointers visible to another process and Remoting does involve Sockets and passing of pointers to class. (Okay Okay, they're called reference)
So, Study Remoting !!.
|
|
|
|
|
Sockets are just one of the many ways to communicate, especially across processes. It's technically possible to pass any pointer using a socket without regards to what it's pointing to.
But if you pass a raw pointer from one process to another (using whatever mechanism, not just sockets), it immediately becomes meaningless because pointers are not portable across processes.
"Real men drive manual transmission" - Rajesh.
|
|
|
|
|
As others have stated, you could pass pointers, but they would be meaningless to the other program since he can't access the memory addresses of the other exe (unless, it's "shared memory", continue reading). Your best bet would be to either transfer all the bytes of the image being referenced (or object, using serialization or other similar methods) or if both programs are local, let the client know where to find the image.
One common form of inter-process communications (IPC) is using "shared memory"[^]. In this case, one application would set up a shared memory pool that others can access. This is typically done for applications that need to work extremely fast (and all have direct access to the shared memory location) and don't want the overhead (or need the flexibility) of other IPC options (such as sockets or pipes).
|
|
|
|
|
UPDATE:
This is within same process. In that case can i simply pass the pointer over socket?
Another catch here is, i need to encode all the data in a XML format before sending across the socket.
C++ Code:
CImage *pImage; //pImage hold the data
Inside XML:
&pImage
Can i do like this?
|
|
|
|
|
If it's within the same application, then yes... but if you're within the same application, why are you using a socket at all?
Sockets are used to enable communications across multiple applications, not within the same application (you could but that doesn't mean you should, it's a lot of overhead for nothing).
|
|
|
|
|
I am unsure why are you using sockets, and I feel that there may be better options to choose from if you're having just one process.
If you could explain the situation with the required information (see this post[^] for help on what information to include in your question), someone here might be able to offer you a good alternative.
"Real men drive manual transmission" - Rajesh.
|
|
|
|
|
It's very interesting.
In my own opinion, it is possible but you need something.
First, Receiver process have to open Sender process(use OpenProcess api with PROCESS_VM_READ) with memory access authority.
Second, Sender process have to allocate class instance on allocated memory located on it's own process memory(I don't know about it but if you use Google, it will appears).
Solving these problems may be difficult and complicated but it is possible, I think.
|
|
|
|
|
Oh yeah, watch out for endian ness.
|
|
|
|
|