I have a critical section that is shared between two threads:
TCriticalSection lock_measDataBuff;
I have declared this variable as global. Now because Delphi style classes must be constructed using operator new, i have modified above declaration as follows:
TCriticalSection *lock_measDataBuff;
Where is the best place to initialize the lock variable using operator new? Where is the best place to finalize the global variable using operator delete? Should it be WinMain method? Constructor of one of the classes accessing lock variable? Or some other place in the code?
I would use std::auto_ptr or boost::unique_ptr to handle all of that for you, eg:
#include <memory>
std::auto_ptr<TCriticalSection> lock_measDataBuff(new TCriticalSection);
As you are creating a global variable, you will need to initialize before you create the threads, which would be main, and the best place to release the memory would be after the threads end
Related
An important part of OOP is to use access specifiers to make member methods and variables inaccessible from outside of the object.
When declaring a function block method is is easy to control the Access Specifier, but I have not found a way to control access to member variables.
Is it possible and if yes, how?
You can actually still access internal variables of an object direcly in code (no pointers), but they are read only. The code completion will not display the internal variables though, but after you finish typing the name structure, you will see no compile errorrs - test := fb1.internalVariable will be a valid read action actually while fb1.internalVariable := 5; will end up giving you an error, saying that the variable is not an input to the function block (or any other object for that matter).
You can also use the hide oder hide_all_locals pragma to suppress local variables being found in auto-complete and crossreference-list (see https://infosys.beckhoff.com/content/1033/tc3_plc_intro/2529654667.html?id=5927203996458905204 )
Every variable that you declare under the VAR section of your Function Block is considered private.
There is no public or private keyword for variables in IEC 61131-3
Another thing you can do if you absolutely want to use public/private keywords is to define properties.
In general, the normal convention is to have read-only variables in the VAR_OUTPUT section of the Function Block and writable variables in the VAR_INPUT section of the Function Block. Again, the VAR section is considered a private section even though you could read this variables with the fbName.var notation or write them through their address (but this is a very bad programming style).
Twincat2 also allowed the variables in the VAR section to be written to with the fbName.var notation but this changed in Twincat3 in order to achieve better incapsulation.
To learn more about programming conventions in the IEC 61131-3 world, I recommend you to read the programming guidelines of the PLCOpen organization:
https://plcopen.org/guidelines/guidelines
How can you safely declare and initialize a global variable used by a Monticello package so you don't get errors during loading? Is doing
Smalltalk at: #VarName put: varValue
in a class-side "initialize" method of one of the package classes enough? (I would prefer not to use shared pools in this case.)
Yes, that's enough. Another option would be to use lazy initialization:
^ VarName ifNil: [ VarName := value ]
I'm curious, why are you using a global variable? In my experience there are only very few cases which can't be solved without using global variables and it is my opinion that in most cases the use of a global variable is a hint for bad design.
The question is: If I want to use global variables in many modules. How should I do?
In my opinion, I think, maybe we could make another module and declare the global variables and then include it to any files that require it or something like that. I think this is a very simple way but the problem is I'm not familiar with Fortran. I don't know how to do it and how normally people do it.
Please give me some easy example.
You can just make a module, perhaps called global
module global
implicit none
real :: my_global_x
integer :: my_global_i
end module
and then you can use it wherever it is needed, in modules
module a
use global ...
end module
in subroutines
...
subroutine s
use global
...
end subroutine
...
or in the main program
program main
use global
implicit none
...
end program
You can also use just a limited number of variables from the module to avoid name-space pollution
use global, only: my_global_x
While modifying an existing program's CASE statement, I had to add a second block where some logic is repeated to set NetWeaver portal settings. This is done by setting values in a local variable, then assigning that variable to a Changing parameter. I copied over the code and did a Pretty Print, expecting to compiler to complain about the unknown variable. To my surprise however, this code actually compiles just fine:
CASE i_actionid.
WHEN 'DOMIGO'.
DATA: ls_portal_actions TYPE powl_follow_up_sty.
CLEAR ls_portal_actions.
ls_portal_actions-bo_system = 'SAP_ECC_Common'.
" [...]
c_portal_actions = ls_portal_actions.
WHEN 'EBELN'.
ls_portal_actions-bo_system = 'SAP_ECC_Common'.
" [...]
C_PORTAL_ACTIONS = ls_portal_actions.
ENDCASE.
As I have seen in every other programming language, the DATA: declaration in the first WHEN statement should be encapsulated and available only inside that switch block. Does SAP ignore this encapsulation to make that value available in the entire CASE statement? Is this documented anywhere?
Note that this code compiles just fine and double-clicking the local variable in the second switch takes me to the data declaration in the first. I have however not been able to test that this code executes properly as our testing environment is down.
In short you cannot do this. You will have the following scopes in an abap program within which to declare variables (from local to global):
Form routine: all variables between FORM and ENDFORM
Method: all variables between METHOD and ENDMETHOD
Class - all variables between CLASS and ENDCLASS but only in the CLASS DEFINITION section
Function module: all variables between FUNCTION and ENDFUNCTION
Program/global - anything not in one of the above is global in the current program including variables in PBO and PAI modules
Having the ability to define variables locally in a for loop or if is really useful but unfortunately not possible in ABAP. The closest you will come to publicly available documentation on this is on help.sap.com: Local Data in the Subroutine
As for the compile process do not assume that ABAP will optimize out any variables you do not use it won't, use the code inspector to find and remove them yourself. Since ABAP works the way it does I personally define all my variables at the start of a modularization unit and not inline with other code and have gone so far as to modify the pretty printer to move any inline definitions to the top of the current scope.
Your assumption that a CASE statement defines its own scope of variables in ABAP is simply wrong (and would be wrong for a number of other programming languages as well). It's a bad idea to litter your code with variable declarations because that makes it awfully hard to read and to maintain, but it is possible. The DATA statements - as well as many other declarative statements - are only evaluated at compile time and are completely ignored at runtime. You can find more information about the scopes in the online documentation.
The inline variable declarations are now possible with the newest version of SAP Netweaver. Here is the link to the documentation DATA - inline declaration. Here are also some guidelines of a good and bad usage of this new feature
Here is a quote from this site:
A declaration expression with the declaration operator DATA declares a variable var used as an operand in the current writer position. The declared variable is visible statically in the program from DATA(var) and is valid in the current context. The declaration is made when the program is compiled, regardless of whether the statement is actually executed.
Personally have not had time to check it out yet, because of lack of access to such system.
Can anyone tell me what the difference is between these 2 lines of code, which one is better to use?
System::String ^MyStr = gcnew System::String(MyStr);
System::String ^MyStr;
Those lines are not equivalent. In the first one, you will get an exception beacuse you're trying to create a String from an uninitialized tracking handle (MyStr). In the second one, MyStr is declared, not defined, it points to garbage and will throw an exception if you attempt to use it. Which one you should use depends on the rest of the code
The second one creates a new handle variable. If it's a local variable, then as #dario_ramos says, it's uninitialized, and your program will likely crash if you try to use the handle before assigning it. If it's a member variable or global, then it will be nullptr.
The first one is similar, although it can only be used for locals or globals (member variables use the ctor-initializer syntax in C++/CLI just like plain C++), and does exactly what you're not permitted to do. It reads the brand new uninitialized handle and passes it to the System::String constructor. If by chance the constructor finishes, a handle to the newly constructed String will be placed into the variable as part of initialization. But because the constructor is trying to make a copy of random garbage (if it's a local) or nullptr (if a global), most likely it will simply crash.
It's a bad idea to use the value of any variable in its own initializer (sometimes you need to use the address, never the value).