Znav |
---|
next | C++ Mapping for Classes |
---|
prev | C++ Mapping for Interfaces |
---|
|
On this page:
Basic C++ Mapping for Operations
...
Wiki Markup |
---|
{zcode:cpp}
NodePrx node = ...; // Initialize proxy
string name = node?->name(); // Get name via RPC
{zcode} |
The proxy handle overloads operator?->
to forward method calls to the underlying proxy class instance which, in turn, sends the operation invocation to the server, waits until the operation is complete, and then unmarshals the return value and returns it to the caller.
...
Wiki Markup |
---|
{zcode:cpp}
NodePrx node = ...; // Initialize proxy
node?->name(); // Useless, but no leak
{zcode} |
This is true for all mapped Slice types: you can safely ignore the return value of an operation, no matter what its type — return values are always returned by value. If you ignore the return value, no memory leak occurs because the destructor of the returned value takes care of deallocating memory as needed.
Normal and idempotent
Operations in C++
...
Because idempotent
affects an aspect of call dispatch, not interface, it makes sense for the mapping to be unaffected by the idempotent
keyword.
Passing Parameters in C++
...
Wiki Markup |
---|
{zcode:cpp}
ClientToServerPrx p = ...; // Get proxy...
p?->op1(42, 3.14, true, "Hello world!"); // Pass simple literals
int i = 42;
float f = 3.14;
bool b = true;
string s = "Hello world!";
p?->op1(i, f, b, s); // Pass simple variables
NumberAndString ns = { 42, "The Answer" };
StringSeq ss;
ss.push_back("Hello world!");
StringTable st;
st[0] = ss;
p?->op2(ns, ss, st); // Pass complex variables
p?->op3(p); // Pass proxy
{zcode} |
You can pass either literals or variables to the various operations. Because everything is passed by value or const
reference, there are no memory-management issues to consider.
Out-Parameters in C++
...
Wiki Markup |
---|
{zcode:cpp}
ServerToClientPrx p = ...; // Get proxy...
int i;
float f;
bool b;
string s;
p?->op1(i, f, b, s);
// i, f, b, and s contain updated values now
NumberAndString ns;
StringSeq ss;
StringTable st;
p?->op2(ns, ss, st);
// ns, ss, and st contain updated values now
p?->op3(p);
// p has changed now!
{zcode} |
...
It is worth having another look at the final call:
Wiki Markup |
---|
{zcode:cpp}
p?->op3(p); // Weird, but well?defined
{zcode} |
...
Wiki Markup |
---|
{zcode:cpp}
MatrixArithmeticPrx ma = ...; // Get proxy...
Matrix m1 = ...; // Initialize one matrix
Matrix m2 = ...; // Initialize second matrix
ma?->squareAndCubeRoot(m1, m2, m1); // !!!
{zcode} |
This code is technically legal, in the sense that no memory corruption or locking issues will arise, but it has surprising behavior: because the same variable m1
is passed as an input parameter as well as an output parameter, the final value of m1
is indeterminate — in particular, if client and server are collocated in the same address space, the implementation of the operation will overwrite parts of the input matrix m1
in the process of computing the result because the result is written to the same physical memory location as one of the inputs. In general, you should take care when passing the same variable as both an input and output parameter and only do so if the called operation guarantees to be well-behaved in this case.
Chained Invocations in C++
...
Wiki Markup |
---|
{zcode:cpp}
p2?->setName(p1?->getName());
{zcode} |
This works exactly as intended: the value returned by p1
is transferred to p2
. There are no memory-management or exception safety issues with this code.
Exception Handling in C++
...
Wiki Markup |
---|
{zcode:cpp}
ChildPrx child = ...; // Get proxy...
try {
child?->askToCleanUp(); // Give it a try...
} catch (const Tantrum& t) {
cout << "The child says: " << t.reason << endl;
}
{zcode} |
...
Wiki Markup |
---|
{zcode:cpp}
void run()
{
ChildPrx child = ...; // Get proxy...
try {
child?->askToCleanUp(); // Give it a try...
} catch (const Tantrum& t) {
cout << "The child says: " << t.reason << endl;
child?->scold(); // Recover from error...
}
child?->praise(); // Give positive feedback...
}
int
main(int argc, char* argv[])
{
int status = 1;
try {
// ...
run();
// ...
status = 0;
} catch (const Ice::Exception& e) {
cerr << "Unexpected run?time error: " << e << endl;
}
// ...
return status;
}
{zcode} |
...
For efficiency reasons, you should always catch exceptions by const
reference. This permits the compiler to avoid calling the exception's copy constructor (and, of course, prevents the exception from being sliced to a base type).
Exceptions and Out-Parameters in C++
...
Info |
---|
This is done for reasons of efficiency: providing the strong exception guarantee would require more overhead than can be justified. |
Exceptions and Return Values in C++
For return values, C++ provides the guarantee that a variable receiving the return value of an operation will not be overwritten if an exception is thrown. (Of course, this guarantee holds only if you do not use the same variable as both an out-parameter and to receive the return value of an invocation).
See Also
...
- Sutter, H. 1999. Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions. Reading, MA: Addison-Wesley.
Znav |
---|
next | C++ Mapping for Classes |
---|
prev | C++ Mapping for Interfaces |
---|
|