Assign string object via std::istream in C++ - string

I'd like to assign std::string *ptr via std::string::operator >> in c++.
I have a class below.
class A{
public:
A(){
ptr = new std::string();
}
A(std::string& file){
ptr = new std::string();
std::ifstream ifs(file);
std::stringstream ss;
ss << ifs.rdbuf();
*ptr=ss.str();
ifs.close();
}
~A(){
delete ptr;
}
void output(std::ostream& stream) const{
stream << *ptr;
}
void input(std::istream& stream) const{
stream >> *ptr;
}
private:
std::string *ptr;
};
int main(void){
std::string file="./file";
std::string dfile="./dump";
std::ofstream ofs(file);
A a(file);
a.output(ofs);
std::ifstream ifs(dfile);
A b();
b.input(ifs);
return 0;
}
Assume "./file" contains a text below:
The first form (1) returns a string object with a copy of the current contents of the stream.
The second form (2) sets str as the contents of the stream, discarding any previous contents.
I confirmed the content of "./dump" is same as "./file".
However, the string object I get(b's *ptr) from b.input("./dump") is just a small string delimitered at space, which is just
The
How can I obtain whole text?
Thanks

stream >> *ptr; reads a single whitespace-delimited word.
To read a whole line, use std::getline:
std::getline(stream, *ptr);
Also note that there's no point in allocating your string dynamically (in fact, in its current state your class will leak memory and cause double-deletes if copied, as pointed out by #aschepler in the comments). The member could be a plain std::string str;.

Related

C++ to C# char[]

C# code:
class Hello{
public void helloWorld(char[] chars){
//do something
}
}
C++ code to call C#:
MyCSDLL::Hello* hello;
//init hello, some calls are ok.
char* myCharPtr;
//init with message
HRESULT result = hello->helloWorld(safeArray, (MyCSDLL::_MyRetVal) _retValPtr);
Adapting from How to create and initialize SAFEARRAY of doubles in C++ to pass to C#
void createSafeArray(SAFEARRAY** saData, char* charPtr)
{
char* iterator = charPtr;
SAFEARRAYBOUND Bound;
Bound.lLbound = 0;
Bound.cElements = 10;
*saData = SafeArrayCreate(VT_R8, 1, &Bound);
char HUGEP *pdFreq;
HRESULT hr = SafeArrayAccessData(*saData, (void HUGEP* FAR*)&pdFreq);
if (SUCCEEDED(hr))
{
do {
*pdFreq++ = *iterator;
} while (*iterator++);
}
}
How to call hello->helloWorld()? it is expecting SAFEARRAY*. The current code gives 80131538 error. How to fix it?
C++ Project is not CLR.
Let's suppose the C# code is this:
namespace ClassLibrary1
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Hello
{
public void helloWorld(char[] chars)
{
...
}
}
}
Then, you can call it with this C/C++ code, for example:
#import "C:\mycode\ClassLibrary1\bin\Debug\classlibrary1.tlb" raw_interfaces_only
using namespace ClassLibrary1;
HRESULT CallHello(wchar_t* charPtr, int count)
{
CComPtr<_Hello> p;
HRESULT hr = p.CoCreateInstance(__uuidof(Hello));
if (FAILED(hr))
return hr;
SAFEARRAY* psa = SafeArrayCreateVector(VT_UI2, 0, count);
if (!psa)
return E_OUTOFMEMORY;
LPVOID pdata;
hr = SafeArrayAccessData(psa, &pdata);
if (SUCCEEDED(hr))
{
CopyMemory(pdata, charPtr, count * 2); // count is the number of chars
SafeArrayUnaccessData(psa);
hr = p->helloWorld(psa);
}
SafeArrayDestroy(psa);
return hr;
}
.NET's char type is unicode, so the binary size is two bytes, the C equivalent is wchar_t (or unsigned short, etc...). So the safearray element type must match that, that's why I used VT_UI2 (VT_R8 that you used is Real of size 8 bytes, so it's equivalent to .NET's double type).
If you really want to use C's char, then you must do some kind of conversion to a 2-byte character.
Also, you can use the SafeArrayCreateVector function which directly allocates a 1-dimension safe array. Don't forget to call cleanup methods.

Converting between WinRT HttpBufferContent and unmanaged memory in C++cx

As part of a WinRT C++cx component, what's the most efficient way to convert an unmanaged buffer of bytes (say expressed as a std::string) back and forth with a Windows::Web::Http::HttpBufferContent?
This is what I ended up with, but it doesn't seem very optimal:
std::string to HttpBufferContent:
std::string m_body = ...;
auto writer = ref new DataWriter();
writer->WriteBytes(ArrayReference<unsigned char>(reinterpret_cast<unsigned char*>(const_cast<char*>(m_body.data())), m_body.length()));
auto content = ref new HttpBufferContent(writer->DetachBuffer());
HttpBufferContent to std::string:
HttpBufferContent^ content = ...
auto operation = content->ReadAsBufferAsync();
auto task = create_task(operation);
if (task.wait() == task_status::completed) {
auto buffer = task.get();
size_t length = buffer->Length;
if (length > 0) {
unsigned char* storage = static_cast<unsigned char*>(malloc(length));
DataReader::FromBuffer(buffer)->ReadBytes(ArrayReference<unsigned char>(storage, length));
auto m_body = std::string(reinterpret_cast<char*>(storage), length);
free(storage);
}
} else {
abort();
}
UPDATE: Here's the version I ended up using (you can trivially create a HttpBufferContent^ from an Windows::Storage::Streams::IBuffer^):
void IBufferToString(IBuffer^ buffer, std::string& string) {
Array<unsigned char>^ array = nullptr;
CryptographicBuffer::CopyToByteArray(buffer, &array); // TODO: Avoid copy
string.assign(reinterpret_cast<char*>(array->Data), array->Length);
}
IBuffer^ StringToIBuffer(const std::string& string) {
auto array = ArrayReference<unsigned char>(reinterpret_cast<unsigned char*>(const_cast<char*>(string.data())), string.length());
return CryptographicBuffer::CreateFromByteArray(array);
}
I think you are making at least one unnecessary copy of your data in your current approach for HttpBufferContent to std::string, you could improve this by accessing the IBuffer data directly, see the accepted answer here: Getting an array of bytes out of Windows::Storage::Streams::IBuffer
I think it's better to use smart pointer (no memory management needed) :
#include <wrl.h>
#include <robuffer.h>
#include <memory>
using namespace Windows::Storage::Streams;
using namespace Microsoft::WRL;
IBuffer^ buffer;
ComPtr<IBufferByteAccess> byte_access;
reinterpret_cast<IInspectable*>(buffer)->QueryInterface(IID_PPV_ARGS(&byte_access));
std::unique_ptr<byte[]> raw_buffer = std::make_unique<byte[]>(buffer->Length);
byte_access->Buffer(raw_buffer.get());
std::string str(reinterpret_cast<char*>(raw_buffer.get())); // just 1 copy

Multhreaded programming in C

I have been given an assignment. There is a dictionary of 25 files and each file has random text involving random IP addresses. The task is to find out and output the count of unique IP addresses among all files using the pthread library in C.
I think I have solved the race condition on count variable by mutual exclusion. But, still there is a bug and the code has different count value in each execution.
Here is the code, please suggest fixes for the bug:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <pthread.h>
#include <string.h>
//declaring structure of arguments to give arguments to thread function
struct arg_struct
{
char *arg1; //argument 1 : to pass directory name to thread function
struct dirent *arg2; //argument 2: to pass file name to thread function
};
//declaring structure of pointer which will point unique ip addresses
struct uniqueip
{
char *ip;
};
struct filenames
{
char full_filename[256];
};
struct uniqueip u[200];
int count=0;// global count variable stores total unique ip addresses.
void *ReadFile(void *thread_no);//thread declaration
pthread_mutex_t mutex;
int main(int argc, char *argv[])
{
DIR *dir; //directory stream
FILE *file; //file stream
struct dirent *ent; // directory entry structure
char *line = NULL; // pointer to
size_t len = 1000; //the length of bytes getline will allocate
size_t read;
char full_filename[256]; //will hold the entire file path with
//file name to read
int x=0;
pthread_attr_t attr;
int rc;
long thread_no;
void *status;
void *ReadFile(void *thread_no);
// check the arguments
if(argc < 2)
{
printf("Not enough arguments supplied\n");
return -1;
}
if(argc > 2)
{
printf("Too many arguments supplied\n");
return -1;
}
struct arg_struct args;
args.arg1 = argv[1];
pthread_mutex_init(&mutex, NULL); // initializing mutex
/* Initialize and set thread detached attribute */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// try to open the directory given by the argument
if ((dir = opendir (argv[1])) != NULL)
{
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL)
{
// Check if the list is a regular file
if(ent->d_type == DT_REG)
{
//Get the number of files first so that we would know number
//of threads to be created
x++;
}
}
}
pthread_t thread[x];
struct filenames filenames[x];
thread_no=0;
// try to open the directory given by the argument
if ((dir = opendir (argv[1])) != NULL)
{
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL)
{
// Check if the list is a regular file
if(ent->d_type == DT_REG)
{
// Create the absolute path of the filename
snprintf(filenames[thread_no].full_filename, sizeof filenames[thread_no].full_filename,
"./%s/%s", argv[1], ent->d_name);
//creating threads to read files
args.arg2 = ent; //assigning file name to argument 2
printf("main: creating thread %ld %s \n", thread_no,ent->d_name);
rc = pthread_create(&thread[thread_no], &attr, ReadFile, (void *) &args);
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
thread_no++;
}
}
// Close the directory structure
closedir (dir);
}
else
{
/* could not open directory */
perror ("");
return -1;
}
/* Free attribute and wait for the other threads*/
pthread_attr_destroy(&attr);
for(thread_no=0; thread_no<x; thread_no++)
{
rc = pthread_join(thread[thread_no], &status);
if (rc)
{
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Main: completed join with thread %ld having a status of %ld\n",thread_no,(long)status);
}
printf("Main: program completed. Exiting.\n");
printf("total no. of unique ip addresses are %d\n",count-1);
pthread_mutex_destroy(&mutex);
pthread_exit(NULL);
return 0;
}
void *ReadFile(void *thread_no)
{ // in thread function
struct filenames *my_data;
my_data = (struct filenames *)thread_no;
char full_filename[256];
FILE *file; //file stream
char *line = NULL;
char *split = NULL;
size_t len = 1000; // pointer to the length of bytes getline will allocate
size_t read;
const char s[2]=" "; //used as string split to get ip address
char *token;
int flag = 0,j;
// open the file
file = fopen(my_data -> full_filename, "r");
// file was not able to be open
if (file != NULL)
{
// Print out each line in the file
while ((read = getline(&line, &len, file)) != -1)
{
split=line;
token = strtok(split,s);
pthread_mutex_lock(&mutex);
if(count==0){
//locking mutex variable to avoid race condition
u[count].ip=malloc(sizeof(token)+1);
strcpy(u[count].ip,token);
printf("%d ------ %s\n",count,u[count].ip);
free(u[count].ip);
count++;
}
pthread_mutex_unlock(&mutex); // unlocking mutex
//comparing recently received ip address to all the stored unique ip address.
for(j=0;j<count;j++)
{
if(!(strcmp(u[j].ip,token)))
{
break;
}
else
{
if(j==count-1){
pthread_mutex_lock(&mutex); //locking mutex variable to avoid race condition
u[count].ip=malloc(sizeof(read));
strcpy(u[count].ip,token);
printf("%d ------ %s\n",count,u[count].ip);
count++;
free(u[count].ip);
pthread_mutex_unlock(&mutex); // unlocking mutex
}
}
}
}
}
fclose(file);
pthread_exit((void*) thread_no);
}
There's several issues in this code.
You only ever create one instance of arg_struct, but you re-use it and pass it to every thread. This means that by the time a thread starts, the value of the arg_struct you passed it may have changed. You need to give each thread its own arg_struct - eg. you could declare an array of them alongside the pthread_t array:
pthread_t thread[x];
struct arg_struct args[x];
A similar problem exists with the struct dirent * pointer inside arg_struct - the data pointed to by the struct dirent * returned by readdir() may be overwritten by the next call to readdir() on the same directory stream. There are a few ways to solve this, but one way is to replace the char *arg1; and struct dirent * in arg_struct with a buffer to hold the filename:
struct arg_struct
{
char full_filename[256]; //will hold the entire file path with
//file name to read
};
The main thread can then be changed to put the filename straight into the arg_struct:
snprintf(args[thread_no].full_filename, sizeof args[thread_no].full_filename, "./%s/%s", argv[1], ent->d_name);
In the ReadFile() function, this creates an array of one element and then tries to write to the (non-existent) second element, which has undefined behaviour:
char * argv[1];
argv[1]= my_data->arg1;
That code can be removed entirely, though - now that main() is constructing the full filename for the thread, the thread can just directly open it from the the arg_struct:
file = fopen(my_data->full_filename, "r");
(The thread doesn't need to worry about argv[1] at all anymore).
Your thread function is reading the shared count variable without holding the mutex - you need to lock the mutex before executing if (count == 0), and don't unlock it until after the for () loop (otherwise, you might get two threads deciding to add an IP to the same array location).
When you try to create a copy of the string you want to store, you aren't allocating enough space: sizeof read is always the fixed size of a size_t variable and isn't related to the size of the string you're copying. You want:
u[count].ip = malloc(strlen(token) + 1);
strcpy(u[count].ip, token);
You don't want to immediately free the u[count].ip, either: you need that string to stay allocated. Remove the free(u[count].ip); lines.
There's some easy optimisations you could make, once you get it working. For example, because count only increases and the u[] array is static below the value of count, you can lock the mutex, save a copy of count then unlock the mutex. Loop up to the saved value of count - if you find the string then you can just move straight onto the next line of your input file. It's only if you don't find the string that you need to re-lock the mutex, then continue from the saved count value up to the current count value (which might have increased in the meantime), adding the new string to the array (and incrementing count) if nececssary.

Qt4: how to send QString inside a struct via QSharedMemory

I have a struct
struct control_data{
int column_number;
QString cell;
};
I need to send it to another thread with the help of QShareMemory. I read that you can't do this because QString contains pointers inside. Any other ways?
You have to serialize your struct to a Byte array. You can always convert your QString to a const char* like this:
myString.toStdString().c_str();
But serializing a QString should work.
The first step is to serialize your struct to a QDatastream using Qt, example here.
Then once your struct can be read and written you can pass it to a shared memory.
A complete example of using QSharedMemory can be found here.
Here is the relevant code:
// First, test whether a shared memory segment is already attached to the process.
// If so, detach it
if (sharedMem.isAttached())
{
sharedMem.detach();
}
...
QBuffer buffer;
buffer.open( QBuffer::ReadWrite );
QDataStream out( &buffer );
out << youStruct;
int size = buffer.size(); // size of int + size of QString in bytes
if ( !sharedMem.create( size ) ) {
return;
}
// Write into the shared memory
sharedMem.lock();
char *to = (char*)sharedMem.data();
const char *from = buffer.data().data();
memcpy( to, from, qMin( sharedMem.size(), size ) );
sharedMem.unlock();

memory corruption while executing my code

# include "stdafx.h"
# include <iostream>
#include <ctype.h>
using namespace std;
class a
{
protected:
int d;
public:
virtual void assign(int A) = 0;
int get();
};
class b : a
{
char* n;
public:
b()
{
n=NULL;
}
virtual ~b()
{
delete n;
}
void assign(int A)
{
d=A;
}
void assignchar(char *c)
{
n=c;
}
int get()
{
return d;
}
char* getchart()
{
return n;
}
};
class c : b
{
b *pB;
int e;
public:
c()
{
pB=new b();
}
~c()
{
delete pB;
}
void assign(int A)
{
e=A;
pB->assign(A);
}
int get()
{
return e;
}
b* getp()
{
return pB;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
c *pC=new c();
pC->assign(10);
b *p=pC->getp();
p->assignchar("a");
char *abc=p->getchart();
delete pC;
cout<<*abc<<endl;
getchar();
}
i'm a noob at c++ and was experimenting when i got to this point. I don't understand why i keep getting a memory corruption message from VS2010. I am trying to replicate a problem which is at a higher level by breaking it down into smaller bits, any help would be appreciated.
From a cursory glance, you are passing a static char array to AssignChar that cannot be deleted (ie when you type "A" into your code, its a special block of memory the compiler allocates for you).
You need to understand what assignment of a char* does (or any pointer to type). When you call n=c you are just assigning the pointer, the memory that pointer points to remains where it is. So, unless this is exactly what you meant to do, you will have 2 pointers pointing to the same block of memory.. and you need to decide which to delete (you can't delete it twice, that'd be bad).
My advice here is to start using C++, so no more char* types, use std::string instead. Using char* is C programming. Note that if you did use a std::string, and passed one to assignChars, it would copy as you expected (and there is no need to free std::string objects in your destructor, they handle all that for you).
The problem occurs when you're trying to delete pC.
When ~c() destructor calls ~b() destructor - you're trying to delete n;.
The problem is that after assignchar(), n points to a string literal which was given to it as an argument ("a").
That string is not dynamically allocated, and should not be freed, meaning you should either remove the 'delete n;' line, or give a dynamically-allocated string to assignchar() as an argument.

Resources