memset structure with std::string contained
No, you cant, it would overwrite the internal state of the string and make bad things happen. You could wrap all the POD stuff in a seperate struct and put that in your current one, that way you could memset that and let the string default construct.
Edit: Just to clarify, the string will almost certainly be storing a pointer to the memory its allocated for storage. The string's constructor will always have run before you can memset it (even if you memset this
in the constructor of your type, the string constructor would run first). So you would be overwriting this pointer value, and instead of pointing to its storage, it would a pointer to NULL, or some other almost definitely invalid value.
Is it okay to memset a struct which has an another struct with Smart pointer member?
No, never use memset
on any structure which is not POD.
However your code isn't doing that, it is only calling memset
on _School
which is POD as it only contains a pointer, calling memset
on _Class
or _Globals
would have undefined behaviour. However I'd prefer removing the memset
and adding a constructor to _School
which initialises pSchool
to nullptr
:
struct _School {
_Class *pSchool;
_School() : pSchool(nullptr) {}
};
You need to use new
in C++ code rather than malloc
as malloc
doesn't call class constructors.
Also note that identifiers starting with underscore followed by an uppercase character are reserved for use by the compiler/standard library.
The complete code would be:
#include <map>
#include <string>
#include <memory>
#include <iostream>
struct Globals{
std::shared_ptr<std::map<int, std::string> > rollNamePair;
};
struct Class {
Globals Globals; // global vars
};
struct School {
Class *pSchool;
School() :pSchool(nullptr) {}
};
int main()
{
School abc;
abc.pSchool= new Class();
abc.pSchool->Globals.rollNamePair = std::make_shared<std::map<int, std::string> >();
(*abc.pSchool->Globals.rollNamePair)[1] = "John";
(*abc.pSchool->Globals.rollNamePair)[2] = "Paul";
std::cout << (*abc.pSchool->Globals.rollNamePair)[1] << "\n";
std::cout << (*abc.pSchool->Globals.rollNamePair)[2];
delete abc.pSchool;
return 0;
}
How to use memset while handling strings in C++?
This declaration
char str[] = "geeksforgeeks";
declares a character array that contains a string that is a sequence of characters including the terminating zero symbol '\0'
.
You can imagine the declaration the following equivalent way
char str[] =
{
'g', 'e', 'e', 'k', 's', 'f', 'o', 'r', 'g', 'e', 'e', 'k', 's', '\0'
};
This call of the function memset
memset(str, 't', sizeof(str));
overrides all characters of the array including the terminating zero.
So the next statement
cout << str << endl;
results in undefined behavior because it outputs characters until the terminating zero is encountered.
You could write instead
#include <iostream>
#include <cstring>
int main()
{
char str[] = "geeksforgeeks";
std::memset( str, 't', sizeof( str ) - 1 );
std::cout << str << '\n';
}
Or the following way
#include <iostream>
#include <cstring>
int main()
{
char str[] = "geeksforgeeks";
std::memset( str, 't', std::strlen( str ) );
std::cout << str << '\n';
}
That is keeping the terminating zero unchanged in the array.
If you want to override all characters of the array including the terminating zero, then you should substitute this statement
std::cout << str << '\n';
for this statement
std::cout.write( str, sizeof( str ) ) << '\n';
as it is shown in the program below because the array now does not contain a string.
#include <iostream>
#include <cstring>
int main()
{
char str[] = "geeksforgeeks";
std::memset( str, 't', sizeof( str ) );
std::cout.write( str, sizeof( str ) ) << '\n';
}
As for this call
memset(str, "t", sizeof(str));
then the type of the second argument (that is the type const char *
) does not correspond to the type of the second function parameter that has the type int
. See the declaration of the function
void * memset ( void * ptr, int value, size_t num );
Thus the compiler issues an error message.
Apart from character arrays (that are used very often even in C++) you can use also the standard class std::string
(or std::basic_string
) that simulates strings.
In this case there is no need to use the standard C function memset to fill a string with a single character. The simplest way to do this is the following
#include <iostream>
#include <string>
int main()
{
std::string s( "geeksforgeeks" );
s.assign( s.length(), 't' );
std::cout << s << '\n';
}
Another way is to use the standard algorithm std::fill
or std::fill_n
declared in the header <algorithm>
. For example
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
int main()
{
std::string s( "geeksforgeeks" );
std::fill( std::begin( s ), std::end( s ), 't' );
std::cout << s << '\n';
}
or
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
int main()
{
std::string s( "geeksforgeeks" );
std::fill_n( std::begin( s ), s.length(), 't' );
std::cout << s << '\n';
}
You even can use the method replace
of the class std::string
one of the following ways
#include <iostream>
#include <string>
int main()
{
std::string s( "geeksforgeeks" );
s.replace( 0, s.length(), s.length(), 't' );
std::cout << s << '\n';
}
Or
#include <iostream>
#include <string>
int main()
{
std::string s( "geeksforgeeks" );
s.replace( std::begin( s ), std::end( s ), s.length(), 't' );
std::cout << s << '\n';
}
memset() or value initialization to zero out a struct?
Those two constructs a very different in their meaning. The first one uses a memset
function, which is intended to set a buffer of memory to certain value. The second to initialize an object. Let me explain it with a bit of code:
Lets assume you have a structure that has members only of POD types ("Plain Old Data" - see What are POD types in C++?)
struct POD_OnlyStruct
{
int a;
char b;
};
POD_OnlyStruct t = {}; // OK
POD_OnlyStruct t;
memset(&t, 0, sizeof t); // OK as well
In this case writing a POD_OnlyStruct t = {}
or POD_OnlyStruct t; memset(&t, 0, sizeof t)
doesn't make much difference, as the only difference we have here is the alignment bytes being set to zero-value in case of memset
used. Since you don't have access to those bytes normally, there's no difference for you.
On the other hand, since you've tagged your question as C++, let's try another example, with member types different from POD:
struct TestStruct
{
int a;
std::string b;
};
TestStruct t = {}; // OK
{
TestStruct t1;
memset(&t1, 0, sizeof t1); // ruins member 'b' of our struct
} // Application crashes here
In this case using an expression like TestStruct t = {}
is good, and using a memset
on it will lead to crash. Here's what happens if you use memset
- an object of type TestStruct
is created, thus creating an object of type std::string
, since it's a member of our structure. Next, memset
sets the memory where the object b
was located to certain value, say zero. Now, once our TestStruct object goes out of scope, it is going to be destroyed and when the turn comes to it's member std::string b
you'll see a crash, as all of that object's internal structures were ruined by the memset
.
So, the reality is, those things are very different, and although you sometimes need to memset
a whole structure to zeroes in certain cases, it's always important to make sure you understand what you're doing, and not make a mistake as in our second example.
My vote - use memset
on objects only if it is required, and use the default initialization x = {}
in all other cases.
memset is causing a crash on std::string assignments
You're overwriting deviceId
's internal data by doing memset
all over it; don't ever do memset
over anything but a POD data type. This is C++, we have constructors. Your code should look something like this:
struct DeviceParams
{
int deviceCount;
struct DeviceNode
{
DeviceNode() : eTransportType() { } // initialise eTransportType
// to 0, deviceId initialises itself
static const int MAX_DEVICE_ID = 256;
static const int MAX_DEVICE_ENTRIES = 10;
std::string deviceId; // Device name to Open
TransportType eTransportType;
} deviceNodes[DeviceNode::MAX_DEVICE_ENTRIES];
};
Then
DeviceParams Param;
// get a pointer to Param in pParam
pParam->deviceNodes[index].deviceId = "some string";
Related Topics
Does Std::Cout Have a Return Value
How to Count Cameras in Opencv 2.3
What's the Real Reason to Not Use the Eof Bit as Our Stream Extraction Condition
Iterator Adapter to Iterate Just the Values in a Map
Delete Calling Destructor But Not Deleting Object
Dependent Name Resolution & Namespace Std/Standard Library
Std::Vector Capacity After Copying
Cut Set of a Graph, Boost Graph Library
Should One Never Use Static Inline Function
Enumdisplaydevices VS Wmi Win32_Desktopmonitor, How to Detect Active Monitors
How to Compare Two Character Strings Statically at Compile Time
How to Call a Pointer-To-Member-Function
How to Convert "Pointer to Pointer Type" to Const
Sorting Std::Strings with Numbers in Them
Sort Filenames Naturally with Qt
Calling a Random Number Generating Member Function Doesn't Produce Entirely Random Numbers
Why "Foo F(Bar());" Can Be a Declaration of a Function That Takes Type Bar and Returns Type Foo