![]() |
|
Spaces home Richard RudekPhotosProfileFriendsMore ![]() | ![]() |
Richard Rudek |
|||||||||||||
|
April 13 Tinkering with STL #2 - Functors and examining the compiler output
All code show here will be compiled using the Professional version of Visual Studio 2005 with Service Pack 1 applied. Compiler version 14.00.50727.762. 1a. Static parameters passed to a Functor In the following code snippet, the integers a and b are statically set to 2 and 1, respectively: // 1a. Functor. int a=2, b=1; if ( std::greater<int>()(a, b) ) cout << "a is Greater then b." << endl; So at compile-time, the compiler should be able able to deduce that the condition (whether a is greater than b) is not going to change at runtime, and hopefully eliminate any conditional checks.
Here is the resulting assembly code, as seen within the Disassembly view in VS2005: // 1a. Functor.
int a=2, b=1;
if ( std::greater()(a, b) )
cout << "a is Greater then b." << endl;
1. 00401007 mov eax,dword ptr [__imp_std::endl (40204Ch)]
2. 0040100C push esi
3. 0040100D push eax
4. 0040100E push ecx
5. 0040100F mov ecx,dword ptr [__imp_std::cout (402044h)]
6. 00401015 push offset string "a is Greater then b." (402134h)
7. 0040101A push ecx
8. 0040101B call std::operator<< > (401210h)
9. 00401020 add esp,0Ch
10. 00401023 mov ecx,eax
11. 00401025 call dword ptr [__imp_std::basic_ostream >::operator<< (402048h)]
Wonderful. No conditional code, at all. Let's step through the assembly code just this once, so you can get a feel for what it's doing. (I added the line numbers above).
Next, I add a proper conditional by assigning the result of the rand function to b. // 1b. Functor. b = (rand() > RAND_MAX/2) ? 2 : 0; if ( std::greater<int>()(a, b) ) cout << "a is Greater then b." << endl; Here is the assembly code it produces: // 1b. Functor.
b = (rand() > RAND_MAX/2) ? 2 : 0;
1. 0040102B mov esi,dword ptr [__imp__rand (4020D0h)]
2. 00401031 call esi
3. 00401033 xor edx,edx
4. 00401035 cmp eax,3FFFh
5. 0040103A setle dl
6. 0040103D sub edx,1
7. 00401040 and edx,2
if ( std::greater()(a, b) )
8. 00401043 cmp edx,2
9. 00401046 jge main+6Bh (40106Bh)
cout << "a is Greater then b." << endl;
10. 00401048 mov eax,dword ptr [__imp_std::endl (402054h)]
11. 0040104D push eax
12. 0040104E push ecx
13. 0040104F mov ecx,dword ptr [__imp_std::cout (40204Ch)]
14. 00401055 push offset string "a is Greater then b." (402134h)
15. 0040105A push ecx
16. 0040105B call std::operator<< > (401240h)
17. 00401060 add esp,0Ch
18. 00401063 mov ecx,eax
19. 00401065 call dword ptr [__imp_std::basic_ostream >::operator<< (402050h)]
Notice how the code from line 10 onwards is almost identical to earlier. Also notice how it uses some creative mathematics to set b (edx register) in lines 3 through to 7. It's interesting enough, so I'll step though it.
Finally, I was interested to see how the compiler behaved if I modified the first code snippet by using a parameter that's been attributed with the volatile keyword. // 1c. Functor. volatile int v=1; if ( std::greater<int>()(a, (int)v) ) cout << "a is Greater then v." << endl; Here is the assembly code: // 1c. Functor.
volatile int v=1;
1. 0040106B mov dword ptr [esp+4],1
if ( std::greater()(a, (int)v) )
2. 00401073 cmp dword ptr [esp+4],2
3. 00401078 jge main+9Dh (40109Dh)
cout << "a is Greater then v." << endl;
4. 0040107A mov edx,dword ptr [__imp_std::endl (402054h)]
5. 00401080 mov eax,dword ptr [__imp_std::cout (40204Ch)]
6. 00401085 push edx
7. 00401086 push ecx
8. 00401087 push offset string "a is Greater then v." (40214Ch)
9. 0040108C push eax
10. 0040108D call std::operator<< > (401240h)
11. 00401092 add esp,0Ch
12. 00401095 mov ecx,eax
13. 00401097 call dword ptr [__imp_std::basic_ostream >::operator<< (402050h)]
Here we can see that v is given a real memory location, and that it does not optimise away the conditional. April 09 Tinkering with STL #1 - creating a Predicate usable by find_if on a vector of string (C++)This article has been completely rewritten since I first published it this morning, and posted my question on the Channel9 forums. So yesterday I was tinkering around with the Standard Template Library (STL), trying to learn better ‘generic’ practices. But ended up getting stuck trying to solve a problem that occurs when you try to create a Predicate of string::compare() - the adaptors end up trying to create a reference of a reference, and the Compiler effectively says, no, go away. OK, now some of you are probably saying: “Um, string ? Why are trying to use string::compare, just use the built-in operators. They have overloads”. Well, as tends to happen with these types of things, it started innocently enough, but was rooted in a stupid mistake. I was converting a Microsoft (ptr_fun) sample which used a vector of char pointers. I thought, that was too old-school, and modified it to use std::string instead. The problem was that I forgot to rename the #include <cstring> to <string>, as was kindly pointed out to me by Sven. Thanks Sven. This had the curious effect of not defining various parts of std::basic_string, such that Functors like equal_to failed to compile with complaints about operator==. Anyway, this lead to me trying to workaround the ‘missing’ operators by attempting to construct a suitable Predicate calling a member function, in this case string::compare(). Anyway, having been suitably embarrassed, I'm still curious about whether it can be done. Say, for example, because I need to use a Class that does define Iterators, but not a full compliment of operator overloads. So let's just start off with the definition of find_if, and then go into to some of the concepts behind what I'm trying to do. Having said that, I suppose I should point out that I'm not an Academic, so I'm probably going to mess up the terminology - but let's give it a crack, anyway... Here's the basic definition of find_if: template<class _InIt, class _Pr> inline _InIt find_if(_InIt _First, _InIt _Last, _Pr _Pred) { ... find_if uses two generic classes: an Input Iterator and a Predicate. OK, an Iterator is pretty easy to understand, but what is a Predicate ? Well in this context, it's a Function that is passed an “item” (dereferenced Iterator) and returns a boolean result. So what find_if does is iterate over a range that you specify via the _First and _Last Input Iterators, and it continues until it either reaches the end of the range, or the Predicate _Pred returns true. When I was first introduced to this algorithm, the predicate would usually be an ordinary C++ function call. That made it easy to understand, but from a practical point of view, a PITA to use. Functors int a=2, b=1; if ( std::greater<int>()(a, b) ) cout << "a is Greater than b." << endl; Notice how in the if statement, I have to explicitly specify the brackets () before the parameter list. That's in addition to explicitly specifying the “Type” Template parameter - <int> in this case. Binding A Binder basically allows you bind one of the parameters of a Function (or Functor), effectively changing a two parameter Function call into single parameter one: bind1st statically binds to the first parameter, and bind2nd with the second parameter. int c=2, d=1; std::binder1st<std::greater<int> > b1fn = bind1st(std::greater<int>(), c); if ( b1fn(d) ) // Equivalent to std::greater<int>()(c, d) cout << "c is Greater then d." << endl; Bringing it all together 1. & 2. After I setup v1, I print out each word using a for loop and Iterators. Next, I tried searching for the word “pearly” using various techniques. 3. Searching using find. Once I had the correct header included, it worked fine. 4. Using find_if and the equal_to Functor, adapted as a Predicate using bind2nd. 5. This is where I run into the reference to reference problem. I attempt to create a Predicate using mem_fun_ref and bind2nd., but I can't get it to compile:
From that point on, I tried breaking up the Predicate into it's various concepts, in the hopes of trying to locate where it was failing. 6. The first thing was trying to get mem_fun_ref working using a parameterless function. Nothing too spectacular here, though I chose to include the explicit call (6.3). 7. Finally, I try to get mem_fun_ref working using a single-parametered function - compare. You'll notice that I could not get the implicit call (7.2) to work. It fails with errors about not being able to deduce the template parameters - compare() has 6 overloads. This therefore means that you must use explicit calls, as shown with 7.3 and 7.4. All in all, it's been an interesting exercise. My original hopes of producing more easily consumed source code has quickly evaporated with the realisation that we must use an explicit call - trying to create a Predicate from a member function worsens the consumability, quite considerably. However, I'd still like to see whether the reference from reference issue can be solved, even though now it's just an academic one. The following code is for a console program: #include <vector> #include <algorithm> #include <functional> #include <string> #include <iostream> int main( ) { using namespace std; // 1. Setup and tinker with a vector of string. vector <std::string> v1; vector <std::string>::iterator Iter1, RIter; v1.push_back ( "Open" ); v1.push_back ( "up" ); v1.push_back ( "the" ); v1.push_back ( "pearly" ); v1.push_back ( "gates" ); // 2. Let's start off by printing out the original sequence. cout << "Original sequence contains: " ; for ( Iter1 = v1.begin( ) ; Iter1 != v1.end( ) ; Iter1++ ) cout << Iter1->c_str() << " "; cout << endl; /////////////////////////////////////////////////////////////////////////// // Now lets try various ways of searching for "pearly" /////////////////////////////////////////////////////////////////////////// const string kSRCH("pearly"); // 3. use std::find RIter = std::find(v1.begin(), v1.end(), kSRCH ); if ( RIter != v1.end() ) cout << "using std::find ->" << *RIter << endl; // 4. use equal_to Functor for predicate. RIter = find_if( v1.begin(), v1.end(), bind2nd ( equal_to<string>(), kSRCH ) ); if ( RIter != v1.end() ) cout << "using std::find_if and equal_to Functor ->" << *RIter << endl; // 5. Now assume the object (std::string) doesn't have the appropriate operator // overloads, but does have a compare() member. DOES NOT COMPILE !. RIter = find_if( v1.begin(), v1.end(), bind2nd (mem_fun_ref<int, string, const string&>(&string::compare), string("pearly") ) ); if ( RIter != v1.end() ) cout << "using std::find_if and mem_func_ref ->" << *RIter << endl; // 6. OK, the above fails. So lets break the above predicate down, and see // what we can get to compile. Well start with a parameterless member // function (method) call. string::size(). size_t z = v1[0].size(); // 6.1 Simulate an iteration, where an item is passed in. z = mem_fun_ref(&string::size)(v1[0]); // 6.2 implicit. z = mem_fun_ref<string::size_type, string>(&string::size)(v1[0]); // 6.3 explicit. // 7. Now let's try single parametered member function (method) function. // string::compare(). v1[0].compare(kSRCH); // 7.1 Simulate a single iteration, again. mem_fun_ref(&string::compare)(v1[0], kSRCH); // 7.2 Doesn't compile: can't deduce template argument. mem_fun_ref<int, string, const string&>(&string::compare)(v1[0], "pearly" ); // 7.3 explicit 1 mem_fun_ref<int, string, const string&>(&string::compare)(v1[0], kSRCH ); // 7.4 explicit 2 // Done. getchar(); } Just to add another data point, I tried compiling this under Ubuntu Linux 7.10 with GCC 4.1.3, and it fails as well (manually edited by me): March 22 Copying Table Row text using Word VBA
Note that you need to show the Control Toolbox in order to place the CommandButtons, and to switch in and out of Design Mode. Word's Macro Language is a form of Visual Basic known as Visual Basic for Applications (VBA). But VBA doesn't support what's know as Control Arrays in Visual Basic proper. So instead, each of the CommandButtons shown above need to have their own click-event procedure. Indeed, you can't even override the default procedure name. So rather than repeating, or hard-coding specifics into each of these procedures, it's better to try and tease-out the functionality and place it into a 'Generic' procedure instead - and that's what I've done here. There are eight CommandButtons in this Document. But the functionality of retrieving the text from each cell within that row lives in a procedure that I named GetTableText. Thus the only thing in the CommandButton's click-event procedure is a call to GetTableText, and nothing else. This makes it easy to add new tables, rows and columns - new buttons simply need to call the GetTableText procedure, and it takes care of the rest. Here's the code: Private Sub GetTableText() If Not Selection.Information(wdWithInTable) Then Exit Sub 'Get Column and Row of cell containing the button that launched this event. Dim c As Long, r As Long c = CLng(Selection.Information(wdStartOfRangeColumnNumber)) r = CLng(Selection.Information(wdStartOfRangeRowNumber)) 'Get all text from each cell in this row, bar the current cell. Dim cels As Cells, i As Long, s As String cels = Selection.Range.Tables(1).Rows(r).Cells For i = 1 To c - 1 s = s & StripJunk(cels(i).Range.Text) & vbTab Next s = Left(s, Len(s) - 1) MsgBox("|" & s & "|") End Sub Private Function StripJunk(ByVal s As String) StripJunk = Trim(Replace(s, vbCr & Chr(7), "")) End Function Private Sub CommandButton1_Click() GetTableText() End Sub Private Sub CommandButton2_Click() GetTableText() End Sub Private Sub CommandButton3_Click() GetTableText() End Sub Private Sub CommandButton4_Click() GetTableText() End Sub Private Sub CommandButton5_Click() GetTableText() End Sub Private Sub CommandButton6_Click() GetTableText() End Sub Private Sub CommandButton7_Click() GetTableText() End Sub Private Sub CommandButton8_Click() GetTableText() End Sub So how does this work ? If Macros are enabled, and your not in Design mode, when you click one of the CommandButtons, it first selects the button, then calls any event procedures associated with the control. In this case, we have procedures for the click event, and each of these simply call the GetTableText procedure - in this case a Sub (Subroutine). The GetTableText subroutine takes advantage of the fact that the Selection object changes with the act of clicking the CommandButton. The first thing, though, is that it checks that the current Selection is indeed within a Table - the very first If statement. The next block of code recovers the row and column information of the current table cell, which is the cell where the CommandButton has been placed. The third block of code recovers all the cells of the appropriate row of the the current table. It then iterates through each of the cells up until the column where the CommandButton was, recovering their text, and building up a string in the s variable. The text from each cell is separated with a tab character, and the StripJunk function is used to remove extraneous characters that are part of Word's housekeeping for table text. Finally, the string is cleaned up (the last tab character stripped off), and the string is shown via a Message box. Additionally, I've also wrapped the Message box text with '|' characters, just to ensure that I am indeed cleaning up the string:
In the picture above, note that I've modified the last table by adding an extra column to the right of the CommandButtons. I did this to highlight the fact that the GetTableText subroutine only copies the text from the cells to the left of the cell which contains the CommandButton. In the picture, I clicked the CommandButton in the second row of the last table. Notice that the Message box only shows the text from columns 1 through to 4, and nothing from columns 5 and 6. March 19 Compaq Presario V6000 power connector retainer
Initially I thought it was like an earlier problem I had with the power socket's centre connection being bad on the motherboard. But having checked for broken/intermittent connections in both the power lead and the connector on the Notebook, it appears to be simply a mechanical issue where the plug pops out of it's connector socket. After a little thought, I whipped up this retainer by carefully bending a paper-clip.
Then bent the other end (left) down at approximately 90 degrees so that it hooks into one of the laptop's case screw recesses. That's not going to be popping out too easily, now. Time will tell... February 15 Using RUNAS.EXE to run as a limited user
With Windows Vista, this is now a built-in and fully integrated feature. Back on earlier versions of Windows, though (such as XP or 2000), whilst you can achieve a similar result, it's not natural, and it is not a fully integrated experience. But what if you want to operate in the opposite fashion - you want to stay logged in as a Administrative or Power User, but want to run certain programs at a lower privilege ? Well you can, though it's once again not a fully integrated experience. Some of you may be aware that when you right-click executables or their shortcuts, you get a RunAs menu option. Unfortunately, this option filters out the lower privileged users. So it's not of any use in this situation. Instead, you have to use RUNAS.EXE, which is a command-line executable program that is shipped with Windows.
In the picture at the left, I've created the shortcut (the yellow folder icon to the right of the Start menu), and I've right-clicked this icon and chosen the Properties menu item. You can see that the Target is 2xExplorer.exe living in Program Files. Add in front of this the following: %windir%\system32\runas.exe /user:test
In this case, I point back to the original executable.
Remember, the user account must have a password set. Additionally the user must have logged into their Desktop at least once from the main login screen. ie There must be a folder for the user in the Documents and Settings folder. One final thing. Because of security restrictions, certain user interface behaviours are specifically prohibited by the Windows Shell. For example, dragging and dropping from a program running as a lower privileged user onto a higher privileged program or desktop simply does nothing. This can be annoying, if your aware of it, and is downright infuriating when your not.
|
||||||||||||
|
|