I usually try to phrase things differently to differentiate between the two a bit better, but it's a good question in any case.
Operator new is a function that allocates raw memory -- at least conceptually, it's not much different from malloc()
. Though it's fairly unusual unless you're writing something like your own container, you can call operator new directly, like:
char *x = static_cast<char *>(operator new(100));
It's also possible to overload operator new either globally, or for a specific class. IIRC, the signature is:
void *operator new(size_t);
Of course, if you overload an operator new (either global or for a class), you'll also want/need to overload the matching operator delete as well. For what it's worth, there's also a separate operator new[] that's used to allocate memory for arrays -- but you're almost certainly better off ignoring that whole mess completely.
The new operator is what you normally use to create an object from the free store:
my_class *x = new my_class(0);
The difference between the two is that operator new just allocates raw memory, nothing else. The new operator starts by using operator new to allocate memory, but then it invokes the constructor for the right type of object, so the result is a real live object created in that memory. If that object contains any other objects (either embedded or as base classes) those constructors as invoked as well.
There might be difference in contexts involving std::initializer_list<>
, e.g.:
Case 1 - ()
and {}
#include <initializer_list>
#include <iostream>
using namespace std;
struct Test2 {
Test2(initializer_list<int> l) {}
};
int main() {
Test2* test3 = new Test2(); // compile error: no default ctor
Test2* test4 = new Test2{}; // calls initializer_list ctor
}
Case 2: (v)
and {v}
struct Value {
};
struct Test3 {
Test3(Value v) {}
Test3(initializer_list<Value> v) {}
};
int main() {
Value v;
Test3* test5 = new Test3(v); // calls Test3(Value)
Test3* test6 = new Test3{v}; // calls Test3(initializer_list<Value>)
}
As stated by Meyers and others there is also a huge difference when using STL:
using Vec = std::vector<int>;
Vec* v1 = new Vec(10); // vector of size 10 holding 10 zeroes
Vec* v2 = new Vec{10}; // vector of size 1 holding int 10
and it is not restricted to std::vector
only
In this case there's no difference though (and initializer_list
ctor is ignored)
#include <initializer_list>
#include <iostream>
using namespace std;
struct Test {
Test() {}
Test(initializer_list<int> l) {}
};
int main() {
Test* test1 = new Test(); // calls default ctor
Test* test2 = new Test{}; // same, calls default ctor
}
There is also a well-known difference in this case
void f() {
Test test{};
Test test2();
}
where test
is default-initialized object of type Test
and test2
is a function declaration.
Best Answer
Let's get pedantic, because there are differences that can actually affect your code's behavior. Much of the following is taken from comments made to an Old New Thing article
Sometimes the memory returned by the new operator will be initialized, and sometimes it won't depending on whether the type you're newing up is a POD (plain old data), or if it's a class that contains POD members and is using a compiler-generated default constructor.
Assume:
In a C++98 compiler, the following should occur:
new A
- indeterminate valuenew A()
- zero-initializenew B
- default construct (B::m is uninitialized)new B()
- default construct (B::m is uninitialized)new C
- default construct (C::m is zero-initialized)new C()
- default construct (C::m is zero-initialized)In a C++03 conformant compiler, things should work like so:
new A
- indeterminate valuenew A()
- value-initialize A, which is zero-initialization since it's a POD.new B
- default-initializes (leaves B::m uninitialized)new B()
- value-initializes B which zero-initializes all fields since its default ctor is compiler generated as opposed to user-defined.new C
- default-initializes C, which calls the default ctor.new C()
- value-initializes C, which calls the default ctor.So in all versions of C++ there's a difference between
new A
andnew A()
because A is a POD.And there's a difference in behavior between C++98 and C++03 for the case
new B()
.This is one of the dusty corners of C++ that can drive you crazy. When constructing an object, sometimes you want/need the parens, sometimes you absolutely cannot have them, and sometimes it doesn't matter.