I am looking at the source code for CodeGear C++ Builder header files. In Source/vcl/forms.pas I find the following lines of code:
procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
var
Instance: TComponent;
begin
Instance := TComponent(InstanceClass.NewInstance); // 메타클래스 이용하여, 인스턴스화
TComponent(Reference) := Instance;
try
Instance.Create(Self); // 폼 생성
except
TComponent(Reference) := nil;
raise;
end;
if (FMainForm = nil) and (Instance is TForm) then
begin
TForm(Instance).HandleNeeded; // 윈도우핸들을 생성
FMainForm := TForm(Instance);
end;
end;
Contextually, what I think is happening is that this procedure creates an instance of type InstanceClass and returns that instance through Reference. In my call, InstanceClass is not TForm, so the second half doesn't matter.
I am confused by TComponent(Reference) := Instance;. Syntactically, what is happening here? Is this assignment by reference? Is this assigning a new TComponent with the instantiator argument Reference being assigned the value? Is TComponent() a type casting?
In the procedure’s signature the formal parameter reference does not indicate a data type, but is declared as a variable parameter.
Typeless parameters are not legal in Pascal, but permitted in dialects such as GNU Pascal and FreePascal.
There, such variable parameters accept actual parameters of any data type.
The compiler will not enforce/restrict permissible data types, but it must be addressable (i. e. literals are not permitted).
dataTypeName(expression) is indeed a typecast (also illegal in Pascal, but allowed by some dialects).
Specifically, dataTypeName(variableName) is a variable typecast.
It will be treated as if variableName was of the named data type.
This is necessary, because in this particular case reference has no associated data type.
No associated data type means, there is no agreed rule in how to access the variable in question (i. e. any read/write access is impossible).
The procedure probably creates an instance of TComponentClass, i. e. the data type of the parameter InstanceClass, but there you should really read the documentation of the NewInstance method.
I can only tell you it’s a descendant of TComponent otherwise it hardly makes sense to typecast to an unrelated class.
The Reference parameter is an untyped var parameter. In C++ terms, it is roughly equivalent to void*, ie the address of any variable can be bound to it. The code is type-casting the Reference to the equivalent of TComponent*& or TComponent** and then assigning the Instance variable (a TComponent* pointer) to the caller's passed variable.
The code is roughly equivalent to the following in C++ (except that metaclasses and virtual constructors don't exist in C++, so this code is actually not usable in C++):
void __fastcall TApplication::CreateForm(TComponentClass* InstanceClass, void* Reference)
{
// this just allocates a block of memory of the required size...
TComponent* Instance = static_cast<TComponent*>(InstanceClass->NewInstance());
// *static_cast<TComponent**>(Reference) = Instance;
reinterpret_cast<TComponent*&>(Reference) = Instance;
try
{
// This is calling the class' virtual constructor
// on the allocated memory. In C++, this would be
// similar to calling 'placement-new' if the class
// type was known statically here...
// new(Instance) InstanceClass->ClassType()(this);
Instance->Create(this);
}
catch (...)
{
// *static_cast<TComponent**>(Reference) = NULL;
reinterpret_cast<TComponent*&>(Reference) = NULL;
throw;
}
if ((!FMainForm) && (dynamic_cast<TForm*>(Instance) != NULL))
{
static_cast<TForm*>(Instance)->HandleNeeded();
FMainForm = static_cast<TForm*>(Instance);
}
}
// Application.CreateForm(TForm, Form1);
Application->CreateForm(__classid(TForm), reinterpret_cast<void*>(&Form1));
To send data to multiple clients I create a TIdThreadSafeStringList in OnConnect and assign it to AContext->Data like so
AContext->Data = new TIdThreadSafeStringList
When the client disconnects, its stringlist is deleted in OnDisconnect like so
delete AContext->Data
However this results in an AV. If I zero the parameter, like so
delete AContext->Data
AContext->Data = NULL
the AV goes away. Is there some auto cleanup I'm not aware of?
Using C++ Builder 10.2.3.
Is there some auto cleanup I'm not aware of?
Yes. TIdContext derives from TIdTask, which owns the Data property. The TIdTask destructor is called after the OnDisconnect event and will free the Data object if it is not NULL.
Another (preferred) way to handle this situation is to instead derive a new class from TIdServerContext and add your TIdThreadSafeStringList to that class (and any other per-client custom functionality you want), eg:
class TMyContext : public TIdServerContext
{
public:
TIdThreadSafeStringList *MyList;
__fastcall TMyContext(TIdTCPConnection *AConnection, TIdYarn *AYarn, TIdContextThreadList *AList = NULL)
: TIdServerContext(AConnection, AYarn, AList)
{
MyList = new TIdThreadSafeStringList;
}
__fastcall ~TMyContext()
{
delete MyList;
}
//...
};
Then assign your class type to the server's ContextClass property at runtime before activating the server, eg:
__fastcall TMyForm::TMyForm(TComponent *Owner)
: TForm(Owner)
{
IdTCPServer1->ContextClass = __classid(TMyContext);
//...
}
Then, you can simply type-cast any TIdContext* pointer belonging to the server to your class type in order to access the TIdThreadSafeStringList (or other functionality):
static_cast<TMyContext*>(SomeIdContext)->MyList->...
This way, you can ignore the TIdContext::Data property altogether, or use it for other purposes, if desired.
Hi any idea how to add event to the constructed button in the run time?
I understand how to build component in the run time, but adding event is another thing. Got any example to explain how it works?
Thanks
A VCL event is just a pointer to a class method for a particular object. You can assign that pointer directly, eg:
__fastcall TForm1::TForm1(TComponent *Owner)
: TForm(Owner)
{
TButton *btn = new TButton(this);
btn->Parent = this;
// set other properties as needed...
btn->OnClick = &ButtonClicked;
/*
behind the scenes, this is actually doing the equivalent of this:
TMethod m;
m.Data = this; // the value of the method's hidden 'this' parameter
m.Code = &TForm1::ButtonClicked; // the address of the method itself
btn->OnClick = reinterpret_cast<TNotifyEvent&>(m);
*/
}
void __fastcall TForm1::ButtonClicked(TObject *Sender)
{
// do something ...
}
I would like to pass a primitive (int, bool, ...) by reference. I found a discussion about it (paragraph "Passing value types by reference") here: value types in Dart, but I still wonder if there is a way to do it in Dart (except using an object wrapper) ? Any development ?
The Dart language does not support this and I doubt it ever will, but the future will tell.
Primitives will be passed by value, and as already mentioned here, the only way to 'pass primitives by reference' is by wrapping them like:
class PrimitiveWrapper {
var value;
PrimitiveWrapper(this.value);
}
void alter(PrimitiveWrapper data) {
data.value++;
}
main() {
var data = new PrimitiveWrapper(5);
print(data.value); // 5
alter(data);
print(data.value); // 6
}
If you don't want to do that, then you need to find another way around your problem.
One case where I see people needing to pass by reference is that they have some sort of value they want to pass to functions in a class:
class Foo {
void doFoo() {
var i = 0;
...
doBar(i); // We want to alter i in doBar().
...
i++;
}
void doBar(i) {
i++;
}
}
In this case you could just make i a class member instead.
No, wrappers are the only way.
They are passed by reference. It just doesn't matter because the "primitive" types don't have methods to change their internal value.
Correct me if I'm wrong, but maybe you are misunderstanding what "passing by reference" means? I'm assuming you want to do something like param1 = 10 and want this value to still be 10 when you return from your method. But references aren't pointers. When you assign the parameter a new value (with = operator), this change won't be reflected in the calling method. This is still true with non-primitive types (classes).
Example:
class Test {
int val;
Test(this.val);
}
void main() {
Test t = new Test(1);
fn1(t);
print(t.val); // 2
fn2(t);
print(t.val); // still 2, because "t" has been assigned a new instance in fn2()
}
void fn1(Test t) {
print(t.val); // 1
t.val = 2;
}
void fn2(Test t) {
t = new Test(10);
print(t.val); // 10
}
EDIT
I tried to make my answer more clear, based on the comments, but somehow I can't seem to phrase it right without causing more confusion. Basically, when someone coming from Java says "parameters are passed by reference", they mean what a C/C++ developer would mean by saying "parameters are passed as pointers".
As dart is compiled into JavaScript, I tried something that works for JS, and guess what!? It worked for dart!
Basically, what you can do is put your value inside an object, and then any changes made on that field value inside that function will change the value outside that function as well.
Code (You can run this on dartpad.dev)
main() {
var a = {"b": false};
print("Before passing: " + a["b"].toString());
trial(a);
print("After passing: " + a["b"].toString());
}
trial(param) {
param["b"] = true;
}
Output
Before passing: false
After passing: true
One of the way to pass the variables by reference by using the values in List. As arrays or lists are Pass by reference by default.
void main() {
List<String> name=['ali' ,'fana'];
updatename(name);
print(name);
}
updatename(List<String> name){
name[0]='gufran';
}
Try this one, This one of the simplest way to pass by reference.
You can use ValueNotifier
And, you can pass it as ValueListenable to classes or methods that needs to know up-to-date value, but should not edit it:
class Owner {
final theValue = ValueNotifier(true);
final user = User(theValue);
...
}
class User {
final ValueListeneble<bool> theValue;
User(this.theValue);
...
}
It provides more functionality than actually needed, but solves the problem.
If ValueNotifier + ValueListenable do not work for you (you want to make sure the client does not listen to every change of the value, or your package is pure Dart package and thus cannot reference Flutter libraries), use a function:
class Owner {
int _value = 0;
int getValue() => _value;
void increase() => _value++;
}
void main() {
final owner = Owner();
int Function() obtainer = owner.getValue;
print(obtainer());
owner.increase();
print(obtainer());
}
Output will be:
0
1
This approach has memory usage related downside: the obtainer will hold the reference to the owner, and this, even if owner is already not referenced, but obtainer is still reachable, owner will be also reachable
and thus will not be garbage collected.
If you do not want the downside, pass the smaller container than the entire owner:
import 'package:flutter/foundation.dart';
class ListenableAsObtainer<T> implements ValueObtainer<T> {
ListenableAsObtainer(this._listenable);
final ValueListenable<T> _listenable;
#override
T get value => _listenable.value;
}
class FunctionAsObtainer<T> implements ValueObtainer<T> {
FunctionAsObtainer(this._function);
final T Function() _function;
#override
T get value => _function();
}
class ValueAsObtainer<T> implements ValueObtainer<T> {
ValueAsObtainer(this.value);
#override
T value;
}
/// Use this interface when the client needs
/// access to the current value, but does not need the value to be listenable,
/// i.e. [ValueListenable] would be too strong requirement.
abstract class ValueObtainer<T> {
T get value;
}
The usage of FunctionAsObtainer will still result in holding the owner from garbage collection, but two other options will not.
Just to make it clear:
void main() {
var list1 = [0,1,2];
var modifiedList1 = addMutable(list1, 3);
var list2 = [0,1,2];
var modifiedList2 = addImmutable(list2, 3);
print(list1);
print(modifiedList1);
print(list2);
print(modifiedList2);
}
List<int> addMutable(List<int> list, int element){
return list..add(element);
}
List<int> addImmutable(List<int> list, int element){
return [...list, element];
}
Output:
[0, 1, 2, 3]
[0, 1, 2, 3]
[0, 1, 2]
[0, 1, 2, 3]
All variables are passed by value. If a variable contains a primitive (int, bool, etc.), that's it. You got its value. You can do with it whatever you want, it won't affect the source value. If a variable contains an object, what it really contains is a reference to that object.
The reference itself is also passed by value, but the object it references is not passed at all. It just stayed where it was. This means that you can actually make changes to this very object.
Therefore, if you pass a List and if you .add() something to it, you have internally changed it, like it is passed by reference. But if you use the spread operator [...list], you are creating a fresh new copy of it. In most cases that is what you really want to do.
Sounds complicated. Isn't really. Dart is cool.
I am calling a function which returns a structure of the type CvBox2D, however I want to check for an error in the function and return NULL if there is an error.
CvBox2D function()
{
...
if(ERROR)
return NULL;
...
}
I am getting an error : cannot convert from 'int' to 'CvBox2D'
Your function return type is CvBox2D, so you can't convert a (NULL) pointer to it.
If you really need to return "nothing" if the check inside the function fails, you can change the return type to a pointer to CvBox2D:
CvBox2D* function()
{
...
}
You will also have to change the way the returned object is created inside your function.
Note that using raw pointers in C++ usually isn't a good idea.
Take a look at std::shared_ptr (available in C++11) if you think you really have to use pointers.
If you want to return some error code, you can do the following:
int function(CvBox2D* output) {
// code...
// Assign to struct.
output->center = ...;
if (error) {
return RC_ERROR_FOO;
}
return RC_OK;
}
Then you call this function using a struct you've already allocated (for example, on the stack):
{
CvBox2D myBox;
int retval = function(&myBox);
if (RC_OK == retval) {
printf("Good! Angle of box: %g", myBox.angle);
} else {
printf("Error: %d", retval);
}
}
Where RC_OK, RC_ERROR_FOO are defined as constant integers, or better, as an enum (if you're using C++).
The other answers solve your problem, but if you want to keep the signature of your function, instead of returning an error code, you should throw an exception.