Remember that C and C++ are actually completely different languages. They share some common syntax, but C is a procedural language and C++ is object oriented, so they are different programming paradigms.
gcc should work just fine as a C compiler. I believe MinGW uses it. It also has flags you can specify to make sure it's using the right version of C (e.g. C99).
If you want to stick with C then you simply won't be able to use new (it's not part of the C language) but there shouldn't be any problems with moving to C++ for a shared library, just so long as you put your Object Oriented hat on when you do.
I'd suggest you just stick with the language you are more comfortable with. The fact that you're using new suggests that will be C++, but it's up to you.
Remember that C and C++ are actually completely different languages. They share some common syntax, but C is a procedural language and C++ is object oriented, so they are different programming paradigms.
gcc should work just fine as a C compiler. I believe MinGW uses it. It also has flags you can specify to make sure it's using the right version of C (e.g. C99).
If you want to stick with C then you simply won't be able to use new (it's not part of the C language) but there shouldn't be any problems with moving to C++ for a shared library, just so long as you put your Object Oriented hat on when you do.
I'd suggest you just stick with the language you are more comfortable with. The fact that you're using new suggests that will be C++, but it's up to you.
You can use e.g. GCC as a C compiler. To ensure it's compiling as C, use the
-x coption. You can also specify a particular version of the C standard, e.g.-std=c99. To ensure you're not using any GCC-specific extensions, you can use the-pedanticflag. I'm sure other compilers have similar options.mallocandcallocare indeed how you allocate memory in C.That's up to you.* You say that you want to be cross-platform, but C++ is essentially just as "cross-platform" as C. However, if you're working on embedded platforms (e.g. microcontrollers or DSPs), you may not find C++ compilers for them.
No,
newanddeleteare not supported in C.
* In my opinion, though, you should strongly consider switching to C++ for any application of non-trivial complexity. C++ has far more powerful high-level constructs than C (e.g. smart pointers, containers, templates) that simplify a lot of the tedious work in C. It takes a while to learn how to use them effectively, but in the long run, they will be worth it.
Method 1 (using new)
- Allocates memory for the object on the free store (This is frequently the same thing as the heap)
- Requires you to explicitly
deleteyour object later. (If you don't delete it, you could create a memory leak) - Memory stays allocated until you
deleteit. (i.e. you couldreturnan object that you created usingnew) - The example in the question will leak memory unless the pointer is
deleted; and it should always be deleted, regardless of which control path is taken, or if exceptions are thrown.
Method 2 (not using new)
- Allocates memory for the object on the stack (where all local variables go) There is generally less memory available for the stack; if you allocate too many objects, you risk stack overflow.
- You won't need to
deleteit later. - Memory is no longer allocated when it goes out of scope. (i.e. you shouldn't
returna pointer to an object on the stack)
As far as which one to use; you choose the method that works best for you, given the above constraints.
Some easy cases:
- If you don't want to worry about calling
delete, (and the potential to cause memory leaks) you shouldn't usenew. - If you'd like to return a pointer to your object from a function, you must use
new
There is an important difference between the two.
Everything not allocated with new behaves much like value types in C# (and people often say that those objects are allocated on the stack, which is probably the most common/obvious case, but not always true). More precisely, objects allocated without using new have automatic storage duration
Everything allocated with new is allocated on the heap, and a pointer to it is returned, exactly like reference types in C#.
Anything allocated on the stack has to have a constant size, determined at compile-time (the compiler has to set the stack pointer correctly, or if the object is a member of another class, it has to adjust the size of that other class). That's why arrays in C# are reference types. They have to be, because with reference types, we can decide at runtime how much memory to ask for. And the same applies here. Only arrays with constant size (a size that can be determined at compile-time) can be allocated with automatic storage duration (on the stack). Dynamically sized arrays have to be allocated on the heap, by calling new.
(And that's where any similarity to C# stops)
Now, anything allocated on the stack has "automatic" storage duration (you can actually declare a variable as auto, but this is the default if no other storage type is specified so the keyword isn't really used in practice, but this is where it comes from)
Automatic storage duration means exactly what it sounds like, the duration of the variable is handled automatically. By contrast, anything allocated on the heap has to be manually deleted by you. Here's an example:
void foo() {
bar b;
bar* b2 = new bar();
}
This function creates three values worth considering:
On line 1, it declares a variable b of type bar on the stack (automatic duration).
On line 2, it declares a bar pointer b2 on the stack (automatic duration), and calls new, allocating a bar object on the heap. (dynamic duration)
When the function returns, the following will happen:
First, b2 goes out of scope (order of destruction is always opposite of order of construction). But b2 is just a pointer, so nothing happens, the memory it occupies is simply freed. And importantly, the memory it points to (the bar instance on the heap) is NOT touched. Only the pointer is freed, because only the pointer had automatic duration.
Second, b goes out of scope, so since it has automatic duration, its destructor is called, and the memory is freed.
And the barinstance on the heap? It's probably still there. No one bothered to delete it, so we've leaked memory.
From this example, we can see that anything with automatic duration is guaranteed to have its destructor called when it goes out of scope. That's useful. But anything allocated on the heap lasts as long as we need it to, and can be dynamically sized, as in the case of arrays. That is also useful. We can use that to manage our memory allocations. What if the Foo class allocated some memory on the heap in its constructor, and deleted that memory in its destructor. Then we could get the best of both worlds, safe memory allocations that are guaranteed to be freed again, but without the limitations of forcing everything to be on the stack.
And that is pretty much exactly how most C++ code works.
Look at the standard library's std::vector for example. That is typically allocated on the stack, but can be dynamically sized and resized. And it does this by internally allocating memory on the heap as necessary. The user of the class never sees this, so there's no chance of leaking memory, or forgetting to clean up what you allocated.
This principle is called RAII (Resource Acquisition is Initialization), and it can be extended to any resource that must be acquired and released. (network sockets, files, database connections, synchronization locks). All of them can be acquired in the constructor, and released in the destructor, so you're guaranteed that all resources you acquire will get freed again.
As a general rule, never use new/delete directly from your high level code. Always wrap it in a class that can manage the memory for you, and which will ensure it gets freed again. (Yes, there may be exceptions to this rule. In particular, smart pointers require you to call new directly, and pass the pointer to its constructor, which then takes over and ensures delete is called correctly. But this is still a very important rule of thumb)
Videos
Sometimes people choose to write "new" before declaring an array or calling a function. But there are some who say it is bad and people should do without it.
But... If you can do without "new", why do people use it in the first place? Everyone talks about pros vs cons but no one talks about what is this "new" and what purpose does it serve.
They both allocate memory on the heap. Am I correct?
So I don't consider myself a CS noob by any means and have wrangled my fair share of systems, but also find myself forgetting my CS classes a bit and was surprised when I pondered this I didn't have a clear answer. So, in C/C++ (assuming a non-optimizing compiler) I know when we have a declaration like int stackVar = 5; that will probably get placed either in a register or on in-memory stack. However, when you call new, you always get a pointer back, because from what I understand, new will mean it always goes to heap. Why is it this way? It seems to me that instantiating makes sense for larger objects because having a pointer to them is less expensive than loading the object itself. But when then do we put things on stack, or is that only primitive data types? What does "instantiating" actually mean in the context of saying Request* r = new Request() for some web API versus the above int r = 5 example? How are the two different?
Object* obj = new Object();
new always return pointer to object.
if you write just Object obj it means that obj will hold the object itself. If it is declared this way inside function then memory will be allocated on stack and will be wiped once you leave that function. new allocates memory on heap, so the pointer can be returned from function. Note that pointer can also point to local (stack) variable also.
Since new returns a pointer, you ought to use
Object *obj = new Object();
In C++11, the using keyword when used for type alias is identical to typedef.
7.1.3.2
A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. It has the same semantics as if it were introduced by the typedef specifier. In particular, it does not define a new type and it shall not appear in the type-id.
Bjarne Stroustrup provides a practical example:
typedef void (*PFD)(double); // C style typedef to make `PFD` a pointer to a function returning void and accepting double
using PF = void (*)(double); // `using`-based equivalent of the typedef above
using P = [](double)->void; // not valid in C++11
using P = auto(double)->void // Fixed thanks to DyP
Pre-C++11, the using keyword can bring member functions into scope. In C++11, you can now do this for constructors (another Bjarne Stroustrup example):
class Derived : public Base {
public:
using Base::f; // lift Base's f into Derived's scope -- works in C++98
void f(char); // provide a new f
void f(int); // prefer this f to Base::f(int)
using Base::Base; // lift Base constructors Derived's scope -- C++11 only
Derived(char); // provide a new constructor
Derived(int); // prefer this constructor to Base::Base(int)
// ...
};
Ben Voight provides a pretty good reason behind the rationale of not introducing a new keyword or new syntax. The standard wants to avoid breaking old code as much as possible. This is why in proposal documents you will see sections like Impact on the Standard, Design decisions, and how they might affect older code. There are situations when a proposal seems like a really good idea but might not have traction because it would be too difficult to implement, too confusing, or would contradict old code.
Here is an old paper from 2003 n1449. The rationale seems to be related to templates. Warning: there may be typos due to copying over from PDF.
First let’s consider a toy example:
template <typename T> class MyAlloc {/*...*/}; template <typename T, class A> class MyVector {/*...*/}; template <typename T> struct Vec { typedef MyVector<T, MyAlloc<T> > type; }; Vec<int>::type p; // sample usageThe fundamental problem with this idiom, and the main motivating fact for this proposal, is that the idiom causes the template parameters to appear in non-deducible context. That is, it will not be possible to call the function foo below without explicitly specifying template arguments.
template <typename T> void foo (Vec<T>::type&);So, the syntax is somewhat ugly. We would rather avoid the nested
::typeWe’d prefer something like the following:template <typename T> using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below Vec<int> p; // sample usageNote that we specifically avoid the term “typedef template” and introduce the new syntax involving the pair “using” and “=” to help avoid confusion: we are not defining any types here, we are introducing a synonym (i.e. alias) for an abstraction of a type-id (i.e. type expression) involving template parameters. If the template parameters are used in deducible contexts in the type expression then whenever the template alias is used to form a template-id, the values of the corresponding template parameters can be deduced – more on this will follow. In any case, it is now possible to write generic functions which operate on
Vec<T>in deducible context, and the syntax is improved as well. For example we could rewrite foo as:template <typename T> void foo (Vec<T>&);We underscore here that one of the primary reasons for proposing template aliases was so that argument deduction and the call to
foo(p)will succeed.
The follow-up paper n1489 explains why using instead of using typedef:
It has been suggested to (re)use the keyword typedef — as done in the paper [4] — to introduce template aliases:
template<class T> typedef std::vector<T, MyAllocator<T> > Vec;That notation has the advantage of using a keyword already known to introduce a type alias. However, it also displays several disavantages among which the confusion of using a keyword known to introduce an alias for a type-name in a context where the alias does not designate a type, but a template;
Vecis not an alias for a type, and should not be taken for a typedef-name. The nameVecis a name for the familystd::vector< [bullet] , MyAllocator< [bullet] > >– where the bullet is a placeholder for a type-name. Consequently we do not propose the “typedef” syntax. On the other hand the sentencetemplate<class T> using Vec = std::vector<T, MyAllocator<T> >;can be read/interpreted as: from now on, I’ll be using
Vec<T>as a synonym forstd::vector<T, MyAllocator<T> >. With that reading, the new syntax for aliasing seems reasonably logical.
I think the important distinction is made here, aliases instead of types. Another quote from the same document:
An alias-declaration is a declaration, and not a definition. An alias- declaration introduces a name into a declarative region as an alias for the type designated by the right-hand-side of the declaration. The core of this proposal concerns itself with type name aliases, but the notation can obviously be generalized to provide alternate spellings of namespace-aliasing or naming set of overloaded functions (see ✁ 2.3 for further discussion). [My note: That section discusses what that syntax can look like and reasons why it isn't part of the proposal.] It may be noted that the grammar production alias-declaration is acceptable anywhere a typedef declaration or a namespace-alias-definition is acceptable.
Summary, for the role of using:
- template aliases (or template typedefs, the former is preferred namewise)
- namespace aliases (i.e.,
namespace PO = boost::program_optionsandusing PO = ...equivalent) - the document says
A typedef declaration can be viewed as a special case of non-template alias-declaration. It's an aesthetic change, and is considered identical in this case. - bringing something into scope (for example,
namespace stdinto the global scope), member functions, inheriting constructors
It cannot be used for:
int i;
using r = i; // compile-error
Instead do:
using r = decltype(i);
Naming a set of overloads.
// bring cos into scope
using std::cos;
// invalid syntax
using std::cos(double);
// not allowed, instead use Bjarne Stroustrup function pointer alias example
using test = std::cos(double);
Another difference between typedef and using: you may do this:
using vector3d_t = double[3];
vector3d_t v = {1,2,3};
v[1] = 4;
It is not possible with typedef:
typedef double[3] vector3d_t; // Compilation error