0

I was trying to guarantee that memory I allocated dynamically is pointing nowhere.

I tried the following

template<typename T>
[...something here...]
T *mem = new T[size];

for ( int i=0; i<size; i++ )
{
    (mem+i) = NULL;
}  
[...something else there...]

Just as one could write

int *pInt = new int;
pInt = NULL;

But it that doesn't work because in the upper example mem isn't an "lvalue"?

Why does this only appear to be the case if I allocate dynamically more the one type-specific memory on the heap?

In addition one strange thing happens if I use a template-function, because it seems to be legal to write

template<typename T>
[...something here...]
T mem = new T[size];

for ( int i=0; i<size; i++ )
{
    *(mem+i) = NULL;

    /* or the equivalent
    mem[i] = NULL;
    */
}  
[...something else there...]

How can it be possible to assign NULL (which is basically the int value 0) to a variable or object that could be basically anything? It might be an int variable, fine, it would work. But what if I called the template function with std::string. It shouldn't work at all, right? So why does it appear to be legal to write something like this?

Is it the freedom to program generic but also the responsibility to watch out, not to invoke some generic function with the wrong type?

trincot
  • 317,000
  • 35
  • 244
  • 286
user3272529
  • 115
  • 9
  • 1
    You cannot assign NULL to everything so what you are attempting to do is impossible. Perhaps you could explain the underlying problem. – David Heffernan Mar 06 '14 at 19:17
  • Post real code. The template makes no sense (try substituting `int` for `T`) – PaulMcKenzie Mar 06 '14 at 19:17
  • You can assign 0 to a variable even if its type is not `int` because of implicit conversions. –  Mar 06 '14 at 19:17
  • 2
    Maybe you mean: T *mem = new T[size]; ? – Leo Chapiro Mar 06 '14 at 19:18
  • 1
    Your code only makes sense if `T` is a pointer type. – japreiss Mar 06 '14 at 19:19
  • Image that there's a pointer to a class, dynamically allocated to 5 elements. Now i would like to make the 2'nd and the 3'rd element to point nowhere, lets say, initialize them. The objects they were pointing to, lets say they don't matter at the moment. But i dont want to use delete, because the memory size, wich has been allocated, should remain allocated, in order to be able to assign some other objects to the nulled pointers. – user3272529 Mar 06 '14 at 19:24
  • `new()` will automatically initialize all elements in the allocated array with the default constructor for that type. Just make sure you properly define one - don't go messing around with re-initializing it all after `new()` returns... – twalberg Mar 06 '14 at 20:06

2 Answers2

1

But it that doesn't work because in the upper example "mem" isn't an "lvalue"?

Indeed, you're trying to reassign the temporary pointer mem+i; that doesn't make sense. Presumably, you want to set the array member (mem[i] or *(mem+i)), to something; although probably not to NULL unless T is supposed to be a pointer type.

In the example with a single object, you're reassigning the only pointer to the allocated object; so you then have no way to use or delete the object.

How can it be possible to assign NULL ( wich is basically the int value 0 ) to an variable or object that could be basically anything?

Because, before C++11, the only valid null pointer constants (and therefore the only valid expansions of the NULL macro) were zero-valued integer constants; so the code expands to something like

*(mem+i) = 0;

which is valid for many types. These days, NULL might (or might not) expand to nullptr, in which case it will only be valid for pointer types.

But what if i called the template function with std::string. It shouldn't work at all, right ?

std::string has a constructor and assignment operator taking a pointer to a C-style string, to allow for example

std::string hello = "Hello, world!";

These can also take a null pointer, giving undefined behavoiur.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
0

Your code is:

for ( int i=0; i<size; i++ )
{
  (mem+i) = NULL;
}

In this case (mem+i) is an temporary result and is called rvalue. rvalues are temporary you must not assign them a value. You can only assign a value to an lvalue. (BTW I think this is not what you want to do: I guess you want to change the memory to which the pointer shows and not the address value stored in the pointer)

for ( int i=0; i<size; i++ )
{
  mem[i] = NULL;
 *(mem+i) = NULL;
}

In this case also temporary results are computed (in both cases mem+i) but the are used to address the correct memory. Thus in both cases the memory which is pointed to is a lvalue.

If you use templates you must keep in mind that these are templates ;-) A template code is never compiled if the template is not used anywhere. And if it is used it depends on what kind of variable/class you use as template argument.

You can write this code:

template<typename T>
void func( T a)
{
  a.foo = "bar";
  a.my_func( 3.14);
}

This code looks strang, but it will compile for each a which is of any structure or class with a member variable/object foo that can be assigned a const charand a member function or function pointer or object with overloaded operator () with the name my_func.

ROTA
  • 101
  • 3
  • Well, i am trying to make a function that allocates memory to a pointer, passed as an argument. The allocation size is also passed as an int value. I wanted to make sure, that the temporary memory points nowhere and only "holds" the type-specific sized memory space. That was at least my thougt. – user3272529 Mar 06 '14 at 19:43
  • What about the following code: `template int get_mem( T* & ptr, int len) { try{ptr=new T[len];} catch(...) {ptr=nullptr; return 1;} for (int i=0; i – ROTA Mar 06 '14 at 20:36