AddObject in TStringList - c++

This is the first time I use AddObject method in C++ Builder 6 in a TStringList
but I can not add an integer to the object list for example. Of course I did it by means of casting different types. But it's not what I want. Please help me do it simpler
and why the objects must be Tobject* in object list
this is my simple program...
#include <vcl.h>
#include <iostream.h>
#include <conio.h>
#pragma hdrstop
#pragma argsused
int main(int argc, char* argv[])
{
int r=random(100+1);
TStringList *mylist=new TStringList;
mylist->AddObject("r",(TObject *)r);
int i=mylist->IndexOf("r");
int a=(int)(mylist->Objects[i]);
cout<<a<<endl;
getch();
return 0;
}

Use a std::map or other suitable container instead, eg:
#pragma hdrstop
#include <iostream.h>
#include <conio.h>
#include <map>
#pragma argsused
int main(int argc, char* argv[])
{
int r = random(100+1);
std::map<std::string, int> mylist;
mylist["r"] = r;
int a = mylist["r"];
cout << a << std::endl;
getch();
return 0;
}

why the objects must be Tobject*
Because of Borland's design of VCL.
mylist->AddObject("r",(TObject *)r);
Do not do this, because there's no guarantee that TStringList wouldn't call some methods of TObject* inside AddObject. For example it can call objectName() or incrementReference() (I know, that there's no TStringList::incrementReference() but it's just an example).
IMHO, all that you need is std::map:
#include <map>
int main()
{
int r=random(100+1);
std::map< AnsiString, int > myList;
myList[ "r" ] = r;
int a = myList[ "r" ];
}

It's very ugly but the cast will work fine. The pragmatic approach is to stick with that method if you must use TStringList.
If you wanted, you could add TObject derived wrappers that hold 'int's to another vector and use these pointers but it require more code to maintain that second list, is more prone to errors and a lot slower.
Alternatively new these wrappers and add them to the stringlist and then manage deletion of the objects manually. This is error prone.
The best approach may be to ditch TStringList if that is possible. Use a struct/class or a std::pair and std::vector or std::deque.
e.g.
typedef std::pair<AnsiString, int> MyValue;
typedef std::vector<MyValue> MyValueList;
MyValueList list;
list.push_back(MyValue("hello", 1));
AnsiString const& s = list[0].first;
int i = list[0].second;

Related

boost::multi_index_container crashes with _com_ptr_t objects

I try to use boost::multi_index_container with _com_ptr_t objects.
Code compiles with no warnings but crashes in runtime.
Standard containers (std::set, map etc) work perfectly with such objects.
Is it possible to use multi_index_container with _com_ptr_t?
Sample code here:
#include "stdafx.h"
#include <boost\multi_index_container.hpp>
#include <boost\multi_index\random_access_index.hpp>
#include <boost\multi_index\global_fun.hpp>
#include <boost\multi_index\ordered_index.hpp>
#import "C:\Windows\SysWOW64\msxml6.dll" exclude("ISequentialStream", "_FILETIME")
using CTest =
boost::multi_index_container<MSXML2::IXMLDOMDocument2Ptr,
boost::multi_index::indexed_by<boost::multi_index::random_access<>>>;
int main()
{
::CoInitialize(nullptr);
CTest tst;
MSXML2::IXMLDOMDocumentPtr doc;
doc.CreateInstance(CLSID_DOMDocument);
tst.push_back(std::move(doc)); <-- crash here
::CoUninitialize();
return 0;
}
I notice that the multi_index_container you've defined holds pointers of type MSXML2::IXMLDOMDocument2Ptr, yet doc is of type MSXML2::IXMLDOMDocumentPtr (without the 2). I'm assuming this is OK, as the problem is really not related to this discrepancy.
Boost.MultiIndex does support move semantics, so you can use std::move as you please.
The actual problem is that _com_ptr_t has a weird, destructive operator& overload returning a pointer to the wrapped interface. This confuses the internal code of Boost.MultiIndex. You can easily bypass this overload as follows:
#include <boost\multi_index_container.hpp>
#include <boost\multi_index\random_access_index.hpp>
#include <boost\multi_index\global_fun.hpp>
#include <boost\multi_index\ordered_index.hpp>
#import "C:\Windows\SysWOW64\msxml6.dll" exclude("ISequentialStream", "_FILETIME")
struct IXMLDOMDocument2Ptr:MSXML2::IXMLDOMDocument2Ptr
{
using MSXML2::IXMLDOMDocument2Ptr::IXMLDOMDocument2Ptr;
IXMLDOMDocument2Ptr* operator&(){return this;}
const IXMLDOMDocument2Ptr* operator&()const{return this;}
};
using CTest =
boost::multi_index_container<IXMLDOMDocument2Ptr,
boost::multi_index::indexed_by<boost::multi_index::random_access<>>>;
int main()
{
::CoInitialize(nullptr);
{
// defined in scope so that destruction happens before CoUninitialize
CTest tst;
MSXML2::IXMLDOMDocumentPtr doc;
doc.CreateInstance(CLSID_DOMDocument);
tst.push_back(std::move(doc));
}
::CoUninitialize();
return 0;
}
Would you mind entering a ticket for this problem at Boost Trac? I can fix the issue internally (by not relying on user-overloadable operator&s) but it's going to take a while till I find the time to do so and I wouldn't like to forget about it.
Postscript
If you have this problem throughout your program, you can automate the fix as follows:
#include <boost\multi_index_container.hpp>
#include <boost\multi_index\random_access_index.hpp>
#include <boost\multi_index\global_fun.hpp>
#include <boost\multi_index\ordered_index.hpp>
#import "C:\Windows\SysWOW64\msxml6.dll" exclude("ISequentialStream", "_FILETIME")
template<typename CComPtr>
struct CFixedAddressofComPtr:CComPtr
{
using CComPtr::CComPtr;
CFixedAddressofComPtr* operator&(){return this;}
const CFixedAddressofComPtr* operator&()const{return this;}
};
template<typename CComPtr,typename TIndexList>
using CComPtrMultiIndexContainer=boost::multi_index_container<
CFixedAddressofComPtr<CComPtr>,
TIndexList
>;
using CTest =
CComPtrMultiIndexContainer<MSXML2::IXMLDOMDocument2Ptr,
boost::multi_index::indexed_by<boost::multi_index::random_access<>>>;
int main()
{
::CoInitialize(nullptr);
{
// declared in scope so that destruction happens before CoUninitialize.
CTest tst;
MSXML2::IXMLDOMDocumentPtr doc;
doc.CreateInstance(CLSID_DOMDocument);
tst.push_back(std::move(doc));
}
::CoUninitialize();
return 0;
}

Boost function map to string

I am trying to map a string to a function. The function should get a const char* passed in. I am wondering why I keep getting the error that
*no match for call to ‘(boost::_bi::bind_t<boost::_bi::unspecified, void (*)(const char*), boost::_bi::list0>) (const char*)’*
My code is below
#include <map>
#include <string>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
typedef boost::function<void(const char*)> fun_t;
typedef std::map<std::string, fun_t> funs_t;
void $A(const char *msg)
{
std::cout<<"hello $A";
}
int main(int argc, char **argv)
{
std::string p = "hello";
funs_t f;
f["$A"] = boost::bind($A);
f["$A"](p.c_str());
return 0;
}
In your example, using boost::bind is completely superfluous. You can just assign the function itself (it will converted to a pointer to a function, and be type erased by boost::function just fine).
Since you do bind, it's not enough to just pass the function. You need to give boost::bind the argument when binding, or specify a placeholder if you want to have the bound object forward something to your function. You can see it in the error message, that's what boost::_bi::list0 is there for.
So to resolve it:
f["$A"] = boost::bind($A, _1);
Or the simpler
f["$A"] = $A;
Also, as I noted to you in the comment, I suggest you avoid identifiers which are not standard. A $ isn't a valid token in an identifier according to the C++ standard. Some implementations may support it, but not all are required to.

C++ crash Segmentation fault: 11

I have been working on a program to test out a few string manipulation possibilities. It is basically supposed to read a string list and be able to find a character's neighbors to go through the strings as a circuit. Here's the code:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
std::string grid[20]={" "};
std::string get(int string, int member){
return grid[string].substr(member,1);
}
std::string* getNeighbors(int string, int member){
std::string neighbors[4];
neighbors[0]=grid[string-1].substr(member,1);//up
neighbors[1]=grid[string+1].substr(member,1);//down
neighbors[2]=grid[string].substr(member-1,1);//left
neighbors[3]=grid[string].substr(member+1,1);//right
std::string* p=neighbors;
return p;//Returns up,down,left,right.
}
int main(int argc, char** argv){
grid[1]="#----^---0";
grid[2]="abcdefghi0";
grid[3]="jklmnopqr0";//TODO Change to read of txt*/
std::string* neighbors;
for(int i=0;grid[1].length()>i;i++){
neighbors=getNeighbors(2,1);
if(neighbors[3]=="-" | neighbors[3]=="^"){
std::string r=get(1,i);
(r!="0") ? std::cout<<r:0;//Dangerous. TODO Unknown symbol handling
std::cout<<neighbors[3];
}
}
}
This compiles well, but has the runtime error "Segmentation fault: 11". I am using several subjects and techniques that I am not used to and am likely misusing. Any help would be great.
std::string neighbors[4]; is stack allocated. When you go out getNeighborsit looses scope. Try to put it other place (even globaly, just as a proof of concept). A better design should be pass this as parater to your function.
void getNeighbors(int string, int member, std::vector<std::string>& neighbors){
;
neighbors[0]=grid[string-1].substr(member,1);//up
neighbors[1]=grid[string+1].substr(member,1);//down
neighbors[2]=grid[string].substr(member-1,1);//left
neighbors[3]=grid[string].substr(member+1,1);//right
}
EDIT:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
std::string grid[20]={" "};
std::string neighbors[4]; //<---------------------------
std::string get(int string, int member){
return grid[string].substr(member,1);
}
std::string* getNeighbors(int string, int member){
neighbors[0]=grid[string-1].substr(member,1);//up
neighbors[1]=grid[string+1].substr(member,1);//down
neighbors[2]=grid[string].substr(member-1,1);//left
neighbors[3]=grid[string].substr(member+1,1);//right
std::string* p=neighbors;
return p;//Returns up,down,left,right.
}
int main(int argc, char** argv){
grid[1]="#----^---0";
grid[2]="abcdefghi0";
grid[3]="jklmnopqr0";//TODO Change to read of txt*/
std::string* neighbors;
for(int i=0;grid[1].length()>i;i++){
neighbors=getNeighbors(2,1);
if(neighbors[3]=="-" | neighbors[3]=="^"){
std::string r=get(1,i);
(r!="0") ? std::cout<<r:"0";//Dangerous. TODO Unknown symbol handling
std::cout<<neighbors[3];
}
}
}
The neighborsnow is global (I don´t like this, but do the job for the POC).
getNeighbors() is returning a pointer to a local variable.

simple c++ function inclusion failure

I am trying to include a function from another file inside a "main" file. I'm following this paradigm:
http://www.learncpp.com/cpp-tutorial/18-programs-with-multiple-files/
Here is my main file, digispark.cpp:
#include <iostream>
using namespace std;
int send(int argc, char **argv);
int main()
{
char* on;
*on = '1';
char* off;
*off = '0';
send(1,&on);
return 0;
}
And here is my send.cpp:
#include <stdio.h>
#include <iostream>
#include <string.h>
#if defined WIN
#include <lusb0_usb.h> // this is libusb, see http://libusb.sourceforge.net/
#else
#include <usb.h> // this is libusb, see http://libusb.sourceforge.net/
#endif
// I've simplified the contents of send for my debugging and your aid, but the
// complicated arguments are a part of the function that will eventually need
// to be here.
int send (int argc, char **argv)
{
std::cout << "Hello";
return 0;
}
I'm compiling on Ubuntu 12.10 using the g++ compiler like so:
g++ digispark.cpp send.cpp -o digispark
It compiles successfully.
However, when I run the program, "Hello" does not come up. Therefore I don't believe the function is being called at all. What am I doing wrong? Any help would be great! Thanks!
EDIT:
How I dealt with the issue:
int send(int argc, char **argv);
int main()
{
char* on[4];
on[0] = (char*)"send";
on[1] = (char*)"1";
char* off[4];
off[0] = (char*)"send";
off[1] = (char*)"0";
send(2,on);
return 0;
}
For those of you who were confused as to why I insisted doing this, as I said before, the send function was already built to accept the char** argv (or char* argv[]). My point was to try to mimic that in my main function.
It would have been much more difficult to rewrite the function that actually goes in the send function to take a different type of argument than just to send in what it wanted. Thanks everyone!
So if this helps anyone trying something similar feel free to use it!
Your problem is not the one you think it is. It's here:
char* on;
*on = '1';
You declared a char pointer, but did not initialize it. Then you dereferenced it. Bang, you're dead. This is what is known as Undefined Behavior. Once you invoke U.B., anything can happen. If you're lucky, it's a crash. But I guess you weren't lucky this time.
Look, if you want to start storing things in memory, you have to allocate that memory first. The best way, as hetepeperfan said, is to just use std::string and let that class take care of all the allocating/deallocating for you. But if for some reason you think you have to use C-style strings and pointers, then try this:
char on[128]; //or however much room you think you'll need. Don't know? Maybe you shoulda used std::string ...
*on = '1';
*(on+1) = '\0'; //if you're using C-strings, better null terminate.
char off[128];
*off = '0';
*(off+1) = '\0';
send(1,&on);
ok I think you try to do something like the following, I tried to make it a bit more in the Style of C++ and prevent the use of pointers since they should not be necessary in the code that you showed.
digispark.cpp
#include "send.h"
int main (int argc, char** argv){
string on = "1";
string off = "0";
send ( on );
send ( off );
return 0;
}
send.cpp
#include <iostream>
#include <string>
void send( const std::string& s) {
std::cout << s << std::endl;
}
send.h
void send(const std::string& s);

Does std::map<key, data> in C++ support native data types like Structures?

How do I map a key to a native data type like structure?
I wrote this snipped but I couldn't compile it. Do you have any ideas on how to fix it?
#include <map>
#include <iostream>
typedef struct _list
{
int a,b;
}list;
map<int,list> test_map;
int main(void)
{
cout <<"Testing"<< endl;
}
map resides in the std:: namespace. Two possible ways to fix this:
using namespace std;
// ...
map<int, list> test_map;
or
std::map<int, list> test_map;
I prefer the second method, but it's a purely personal choice.
On a related note, there is no real limitation on what you can put in a map, aside from the fact that they must be copyable/assignable, and that the key type must have a < operator (or you can also provide a comparer functor).
EDIT: Seems like <list> is included somewhere, either in <iostream> (unlikely) or <map> (strange but not impossible). A using namespace std will cause std::list to clash with your own struct. The solution: rename your struct, or remove the using namespace and put std:: where it's needed.
Added std where required.
Renamed list to mylist to avoid clash with std::list. Avoid typenames and variable names that clash with common usage.
Now compiles OK in VS2008.
#include <map>
#include <iostream>
typedef struct _list
{
int a,b;
} mylist;
std::map<int,mylist> test_map;
int main(void)
{
std::cout <<"Testing"<< std::endl;
return 0;
}
There's no issue with using your struct in the STL containers provided it's copyable cleanly (copy constructor), assignable (implements operator=) and comparable (implements operator<).
A number of problems here:
You're missing either a using::std or std::map, so the compiler doesn't know what map<int,list> means.
Assuming you have a using namespace std declaration, your typedef list might collide with the STL collection of the same name. Change the name.
Your typedef struct _tag {...} tag; construct is an archaic holdover from the 80's. It is not necesarry, and frankly rather silly. It gets you nothing.
Here's your code fixed:
#include <map>
#include <iostream>
struct MyList
{
int a,b;
};
std::map<int,MyList> test_map;
int main(void)
{
std::cout <<"Testing"<< std::endl;
return 0;
}
map<int, _list> test_map; or don't use list(much better) as a name of structure. (You probably also have
#include <list>
...
using namespace std;
somewhere in your code.
I would try to avoid using codepad at all.
I have done a couple of tests with your code and it seems that
it is adding an implicit (and unwanted) using namespace std --it does not require you to qualify map, cout or endl.
it is (probably) including more standard headers than you might want, including #include <list>.
That means that when the compiler looks at the code it is seeing two list, your version and the one in std. Because of the using directive, both are in scope in the line where you create the map and the compiler is not able to determine which to use.
Two simple things that you can do: change the name of your type for the simple test to something other than list (ouch! the tool forcing your naming choices!) or fully qualify the use:
#include <map>
struct list {
int a,b;
};
std::map< int, ::list > the_map;
// ...
Note that codepad is adding the include by itself and the using directive, so it will also compile:
struct list {
int a,b;
};
map<int,::list> the_map;
But that piece of code is wrong
You seem to be comming from C. Try this:
#include <map>
#include <iostream>
struct list
{
int a,b;
};
std::map<int,list> test_map;
int main(void)
{
std::cout <<"Testing"<< std::endl;
return 0;
}