When are member data constructors called? - c++

I have a global member data object, defined in a header (for class MyMainObj) like this.
class MyMainObj
{
MyDataObj obj;
}
MyDataObj has a default constructor.
When is the constructor for MyDataObj called?
Is it called as part of the creation of MyMainObj?

MyDataObj in this case is not a member of MyMainObj, it's a local variable.
But, constructors for data members are called in your class's constructor. The default constructor for every member is called before execution reaches the first line in the constructor, unless you explicitly specify a constructor using an initializer list, in which case that constructor is called instead.

With that code, obj isn't a member of MyMainObj -- it's simply a local object inside that constructor. As such, it'll only be constructed when/if that constructor is invoked.

Concerning your code, you have a function with a variable inside. Upon entering the function, you will run to the line of code that declares the variable, and the constructor will be run then.
But you say "creation of MyMainObj". It's a function, it can only be called, not created.
This is all concerning the title question, "when are members constructed?" This would apply if MyMainObj was a class and not a function.
Your member objects are constructed in the order of which they appear in the class declaration. All objects are full constructed upon entering the constructor. (But this does not include the class itself!)
That is to say, by the time the class enters its constructor, all the members have finished their constructor.
Objects are destructed in reverse order, in the destructor (after the destructor is run).
In a pseudo-diagram:
MyClass
Member1
Member2
Member3
Construction:
Member1
Member2
Member3
MyClass
Destruction:
MyClass
Member3
Member2
Member1
You can manually call the members constructor using an initialization list:
class foo
{
public:
foo(void) : i(0) // construct i with 0.
{
}
int i;
};
There are various question on SO about initialization lists. Initialization list order, Copy-construction initialization list, and more.

Yes, the constructor would be called whenever a MyMainObj instance is created.
I'm a bit confused by the "global member" terminology - the way you've declared that object it would be a local variable inside the constructor. Am I missing something here?

Yes, as other stated the member will be created on the owner class creation, on construction (be it generated by the compiler or with a provided constructor).
The order of creation will be the same as how your members apear in the class declaration. For example :
class MyType
{
Thing a;
Thing b;
Thing d;
Thing c;
};
Whatever constructor is used, whatever the order in a initialization list, the members will be constructed in this order : a, b, d, c. Once it's all done, the constructor code will be executed (if it exists) and only then your whole object will be constructed.

Upon entering an object constructor, memory has already been allocated for it. Then the execution order is as follows:
Base class constructor, if any, as specified in the initialisation list; if not specified, the default constructor is used.
The constructors for the member data, as specified in the initalisation list (default if not specified), in the order they are declared in the class definition. The order in which they are specified in the initialisation list is irrelevant.
The constructor body.
In the example set in the question, the first thing that would be executed upon entering the default constructor of MyMainObj would be the default constructor of MyDataObj to construct the member data obj.

Given a class A:
class A {
MyDataObj obj;
}
If you don't write the constructor for A, the compiler will create one for you, which will create obj as part of constructing A (and destroy obj as part of destroying A.
If you do write a constructor for A, then obj will be created before your constructor runs, although you can reassign it:
class A {
MyDataObj obj;
public:
A() { } // obj created, but the value may or may not be predictable
}
class AA {
MyDataObj obj;
public:
AA()
{
obj = MyDataObj(5);
}
}
class AAA {
MyDataObj obj;
public:
AAA() : obj(5) { } // member initializer list, my preferred method
}
With the third option, the data objects are created before the member initializer list runs, and the values are assigned in the order they are declared in AAA, NOT the order they are listed in the member initializer list.
UPDATE: There is a difference between creation and initialization. Space for the data members (and the base classes, and the data members for the base classes) is always set aside -- which I would call "creation." However, that doesn't mean a useful value is stored in that memory. There are separate rules for whether an object is default initialized, which depend on the type of the data member (primitive, POD, non-POD) and, IIRC, the storage class of the main object (local, static, global). The easiest way to avoid surprises in this area is to simply make sure you explicitly initialize everything.

Related

Is a default constructor called on a class member variable if I am explicitly constructing it in the class constructor in c++?

So if I have something like the following:
class MyClass{
public:
MyClass(){
// do other stuff
*oc = OtherClass(params);
}
private:
OtherClass* oc;
}
When is a constructor called on OtherClass? Would its default be called once as soon as the MyClass initialization begins, and then be redefined with its value constructor during the MyClass constructor? Or does it just not exist during "//do other stuff". What if no default constructor is provided for other class, only a value? Would it be good practice to construct it where it is defined as a member variable?
A default constructor is one that can be called without parameters. For example this is a default constructor:
struct foo {
foo(){} // (should not actually be user defined)
};
This is also a default constructor:
struct bar {
bar(int x = 42) {}
};
In your code it might be that the constructor that is called is a default constructor, but it does not matter for your code, because you do pass a parameter.
When is a constructor called on OtherClass?
In the line *oc = OtherClass(params);.
Would its default be called once as soon as the MyClass initialization begins, and then be redefined with its value constructor during the MyClass constructor?
If you do not provide an initializer members are default initialized. Confusingly for a pointer this means it is not initialized.
Or does it just not exist during "//do other stuff".
The member does exist before, but its value is indeterminate. You cannot use the value without invoking undefined behavior.
What if no default constructor is provided for other class, only a value?
See above. The existance of a default constructor of OtherClass is not relavant here. It would be relevant if the member was OtherClass and not a pointer, because for members of class type default initialization calls the default constructor.
Would it be good practice to construct it where it is defined as a member variable?
It is good practice to provide an initializer for members rather than assign in the constructor:
class MyClass{
public:
MyClass() : oc(params) {
}
private:
OtherClass oc;
}
I replaced the member with an instance rather than a pointer, because using a raw pointer as member opens up a can of worms that would require an even longer answer. For more on that read What is The Rule of Three?. Note that when the member is not a pointer but a OtherClass then suddenly it matters if OtherClass has a default constructor, because if you do not provide an initializer, then the member will be default constructed. Though in the above I used the member initializer list and the member will be initialized by the constructor that takes one parameter.
ÓtherClass *oc; is a pointer and as such has no constructor. It has to be initialized to a valid object before you can dereference it.
You can ensure oc is initialized by, well, initializing it:
MyClass() : oc(new OtherClass()) {
...
*oc = OtherClass(params);
}
This will create a dummy oc when the class it created and then copy or move assign the real object to *oc later. This is wasteful, so why not initialize it with the final value directly:
MyClass() : oc(new OtherClass(params)) {
...
}
or if you have to compute params first:
MyClass : oc(nullptr) {
...
oc = new OtherClass(params);
}
Initializing oc with nullptr first isn't required but it is dirt cheap and it ensures accidentally using oc will access a nullptr and fail instead of oc being some random value that might not crash.
You can also, and better, ensure initialization by inlineing that:
class MyClass {
...
private:
OtherClass *oc(nullptr);
}
With that the compiler will initialize oc whenever you don't initialize it in an initializer list in the constructor.
That said: Do you really need a pointer there? You need a destructor, copy/move constructors and aissgnment operators to handle the pointer directly. An Otherclass oc; would be much easier to deal with.
But if you do need a pointer then you should use a smart pointer to handle ownership for you. That means use std::unique_ptr or more likely std::shared_ptr for it. You might not even need anything past the constructor that way. But think about what it means for copy/move to have the pointer shared. Read about the rule of 0/3/5.

Can constructor do any hard job other than passing values to members?

So to summarize initialization in C++ , constructor can
initialize primitive types to garbage values in memory
call default constructors on members automatically
initialize member objects with nontrivial constructors in init list
but it cannot init array properly. Ref:
C++: constructor initializer for arrays
My question is: how can I do meaningful initialization in the function body? Before entering the braces, everything has already been initialized in one way or another. The braces only contain cleaning up work, things like cout<<"This object is constructed!"
. Ref:
Use of constructor in C++
What if I want to preprocess parameter before passing it to the constructor of member object? For example:
class Foo{
public:
int x;
Foo(int y){
x = y;
}
};
class Bar{
public:
Foo foo1;
Bar(int y){
int z = superComplicatedOperation(y);
// and all other heavylifting work
foo1 = A(z);
}
};
The code above does not compile because compiler tries to init foo1 before entering the braces in constructor.
I have seen suggestions on solving this problem by providing a default constructor to Foo. So the constructor of Bar will first init foo1 to garbage value, and then assign foo1 to something meaningful in the ctor body. This is also the solution to array initialization in the quoted thread. But isn't "initializing to garbage value" an oxymoron? If the compiler wants me to do that, then it wouldn't complain about having no default ctor.
In a word, ctor is supposed to init the object in a user defined way, but I don't see any way to do a nontrivial init. Am I missing something here?
================================================================================
Clarifications: I am askingI am well aware of the Bar(int y): foo(superComplicatedOperation(y)) syntax. My question is on how to do it nicely. From a design point of view, I believe that codes in superComplicatedOperation() really should belong to the ctors. For example, say Bar takes 2 parameters (int x,int y) to initialize. We can imagine they are xy coordinates on plane. Foo also takes coordinates, but with a different reference frame. Then I need
Bar(int x,int y):foo(f1(a,b),f2(a,b))
And this kind of things quickly get ugly if ctor has a handful of params. Besides, init list looks crowded.
And if ctor body "touches" member objects, it means init list does not set members to a desired state, but rather some default zero-like states(e.g. empty vector). Therefore when calling ctor, first memory for the Bar is allocated, then members objects(subchunks of memory) go through the phases:
garbage value/uninitialized
--- init list or default member ctor --->
default "zero-like" state
--- ctor body -------------------------->
actually desired initial state
So initialization is supposed to be a two step process?
Preprocessing a parameter is fairly trivial:
class Bar
{
Foo foo;
Bar(int y) : foo(superComplicatedOperation(y)) {}
}
or you can use a C++11 delegating constructor:
class Bar
{
Foo foo;
Bar (SuperComplicatedData z) : foo(z) {}
Bar (int y) : Bar(superComplicatedOperation(y)) {}
}
What can you do in a constructor function body? Lots of things: fill containers, configure member objects, set up member object relationships, etc.
[...] constructor can
initialize primitive types to garbage values in memory
call default constructors on members automatically
This is default-initialization, which applies to every member that's not specified in the initializer list and do not have an initializer in the class definition.
initialize member objects with nontrivial constructors in init list
The member initializer list can also initialize primitive members.
but it cannot init array properly. Ref:
C++: constructor initializer for arrays
One of the answers there noted that this can now be done in C++11.
My question is: how can I do meaningful initialization in the function
body? Before entering the braces, everything has already been
initialized in one way or another. The braces only contain cleaning up
work, things like cout<<"This object is constructed!" . Ref:
Use of constructor in C++
Um...no. Frequently there's substantial logic in the constructor body proper. It's definitely not only for "cleaning up". It is true that at the time you enter the constructor body every member is initialized in some way (which may include "not initialized at all" for primitive types), but nothing says you can't assign to them or otherwise modify them. Sometimes you have to if there's some sort of circular dependencies. Sometimes the code to compute the stored value is long enough that it's far more readable inside the constructor body.
The code above does not compile because compiler tries to init foo1
before entering the braces in constructor.
I have seen suggestions on solving this problem by providing a default
constructor to Foo.
Well, you can do : foo1(A(superComplicatedOperation(y)) in your example.
So the constructor of Bar will first init foo1 to
garbage value, and then assign foo1 to something meaningful in the
ctor body. This is also the solution to array initialization in the
quoted thread. But isn't "initializing to garbage value" an oxymoron?
If the compiler wants me to do that, then it wouldn't complain about
having no default ctor.
A default ctor means that a object constructed with it is a valid object. A default ctor doesn't necessarily leave members uninitialized (or "initialized to garbage values"). Consider the default ctor for a std::vector, it had better set its internal state to something that represents an empty vector!
More fundamentally, the job of constructors (default or not) is to establish the object's invariants upon which the functions that operate on the object depend. Some objects may have no invariants, but many do (for instance, vector's internal pointer had better be either a valid pointer or null). If you have no default constructor, the compiler has no way of creating a valid object when no argument is supplied; it can't just give you something "initialized to garbage value", because it has no way of knowing whether that can in fact be a valid object of that type.
You can use an initializer list, as you should for any member variables you need to initialize.
You may prefer to initialize things to sane values and then have a function that can set the values later. It's not as clean, but if you plan to construct many objects and you can precompute the value for many of them at once it may save you some time rather than calculating the values for each object.
#include <iostream>
int superComplicatedOperation(int a)
{
return a * 10;
}
class Foo
{
public:
int x;
Foo(int y)
: x(y)
{
}
};
class Bar
{
public:
Foo foo1;
Bar(int y)
: foo1(superComplicatedOperation(y))
{
}
};
int main()
{
Bar b(7);
std::cout << b.foo1.x << "\n";
return 0;
}
class Bar {
public:
Foo foo1;
Bar(int y) : foo1(superComplicatedOperation(y)) { }
};
You can use the Constructor's initialization list for this work. It passes the values to the Ctors of the members for the first creation, this prevents the creation of a garbage object.
I guess I don't understand. I wrote code in the 1990s which has a constructor with hundreds of lines of code which does all kinds of things: opens files, instantiates dozens of objects which create linked lists and arrays based on processing file data. It certainly can initialize an array properly.

Methods called for object in c++ [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
What methods are called when we create an object of a class in c++ or what exactly happens when we create an object of a class.
Without additional information, you should assume that one and only one member function of the class itself is called, the constructor.
class CheesePizza {
public:
CheesePizza() {}
};
CheesePizza barely; // will initialize by calling Foo::foo().
There are many cases in which additional functions might be called, for instance if you create a conversion scenario where a temporary object must be created, such as specifying a std::string argument and passing a const char* value.
class DIYPizza {
std::string m_toppings;
public:
DIYPizza(const std::string& toppings) : m_toppings(toppings) {}
};
DIYPizza dinner("all of the toppings");
This has to create a temporary std::string from the const char* argument, "all of the toppings". Then the DIYPizza::DIYPizza(std::string) operator can be passed this temporary (rvalue), and then subsequently we initialize m_str from it which invokes the std::string(const std::string&) copy constructor to initialize m_str.
What essentially gets done is:
// create a std::string object initialized with the c-string.
std::string rvalueString = std::string("all of the toppings");
// now we have a string to pass to DIYPizza's constructor.
DIYPizza dinner(rvalueString);
However - we're still only calling ONE member function of Foo at this point. The only way for more class members to be invoked is by calling them from whichever constructor is invoked.
class DinnerAtHome {
void orderPizza();
void drinkBeer();
void watchTV(); // I was going with something more brazen, but...
public:
DinnerAtHome() {
orderPizza();
drinkBeer();
watchTV();
drinkBeer();
// arrival of pizza is handled elsewhere.
}
};
Now when you construct a new DinnerAtHome, 5 member functions will be invoked: DinnerAtHome::DinnerAtHome() and the four member-function calls it makes.
Note: "new" is not a member function, it is a global operator.
IF the answer was "five" then either the interviewer was using a trick question or you missed some nuance of what was being asked.
Ok I try overkill answer since no once already selected an answer:
When you create an object the constructor is called, this also involves a call to underlying constructors of members objects, if the object inherits from another object you need also to call constructors of base classes
class Foo: public Bar{
std::vector<int> indices; //default constructor for indices is called
public:
Foo(int a):Bar(a){ //you have to call constructor of Bar here
//else compiling error will occur
}
};
Default constructor is called implicitly for objects that has it. When you create something with "new", first memory is allocated then object is constructed on top of that memory (placement new works in a similiar way, but the chunk of memory may be created explicity by the user elsewhere).
Note that in certain cases you don't know order of constructors calls:
CASE 1
Obj1* myobj= new Obj1 ( new Obj2, new Obj3( new Obj4) );
in this case you have no clues if Obj4 is created before or after Obj2 and if Obj3 is created before or after Obj2, simply the compiler will try to choose "an order" (that may vary depending on compiler and platform), also this is a highly unsafe code:
assume you get exception in Obj3 when Obj2 was already created, then Obj3 memory will never get deallocated (in that extreme case you may find usefull tools for those kinds of problems : Hypodermic / Infectorpp )
see also this answer
CASE 2
static/global variables may be initialized in different orders, and you have to rely on specific compiler functions to declare a initialization order
for GCC:
void f __attribute__((constructor (N)));
also note that "Constructor" is not a "method" like others, infact you cannot save constructor in a std::function nor bind it with std::bind. The only way to save a constructor is to wrap it with a factory method.
well that should be 5 "things" as you mentioned in the interview.
Lets assume your class is called CMyClass.
#include "MyClass.h"
/* GLOBAL objects */
static CMyClass g_obj("foo"); // static makes this object global to this file. you can use it
// anywhere in this file. the object resides in the data segment
// (not the heap or the stack). a string object is created prior
// to the constructor call.
int main(void)
{
....
if (theWorldEnds)
{
/* STACK */
CMyClass obj1; // this calls the constructor CMyClass(). It resides on the stack.
// this object will not exist beyond this "if" section
CMyClass obj2("MyName"); // if you have a constructor CMyClass(string&), the compiler
// constructs an object with the string "MyName" before it calls
// your constructor. so the functions called depend on which
// signature of the constructor is called.
/* HEAP */
CMyClass *obj3 = new CMyClass(); // the object resides on the heap. the pointer obj3
// doesn't exist beyond the scope of the "if" section,
// but the object does exist! if you lose the pointer,
// you'll end up with a memory leak. "new" will call
// functions to allocate memory.
}
}
If you are creating a class means you are calling constructor of that class. If constructor is not in your code than compiler will add the default constructor. YOu can override default constructor to perform some task on object creation.
For
Example:
If you are creating a object of type Person
Person* objPerson = new Person();
It means you are calling Person() method(constructor) of that class.
class Person {
public:
Person() {
// ...
}
};
When an object of a class is instantiated : memory required by the object of the class (depending on its data members) is allocated on the heap and a reference to that memory location is stored by the object name. This individual data members at this memory location on the heap may or may not be initialized depending on the constructor called.
When a new object is constructed, the constructor of the class is invoked to initialize non-static member variables of the class (if the class does not have any constructors, compiler assigns a an empty constructor for the class and invokes it). The constructor may invoke other functions (either library or user-defined functions), but that depends on the functions that programmer has invoked inside the constructor. Also, if the class is part of an inheritance hierarchy, appropriate constructor of base classes are called by compiler before the constructor of the class being instantiated (visit here for a brief explanation).

What is the role of a default (implicit) constructor exactly?

From Thinking in C++
The first hidden argument to the constructor is the this pointer. this pointer holds the address of the caller object. In the case of constructor this pointer points towards an uninitialized block of memory. It is the job of the constructor to initialize this block of memory properly.
So, basically, the constructor is used to get a pointer to the object's space in RAM? Is that correct?
How does the default constructor initialize that memory? Does it get initialized to zero?
The role of the default constructor is the same as any other constructor: To initialize the object. The default constructor (or a constructor with only default arguments) sets member variables to a known state, like setting pointers to nullptr (or 0), etc.
Lets say we have this structure:
struct Foo
{
int a;
int* b;
// Default constructor
// Set `a` to `1`, and `b` to `nullptr`
Foo() : a(1), b(nullptr) {}
};
Now when you declare an instance of the Foo class, then you know what state the member variables will have. If there wasn't a constructor, a normal local variable instance of the Foo class would have undefined values for the a and b members.
If you don't provide a constructor at all, default or other, then the compiler will make a default constructor for you (one is needed, or you would not be able to create instances of the classes), but it will not do any initialization of members.
The hidden argument talked about, is the variable known as this, and it exists for all member functions which are not static.
So, basically, the constructor is used to get a pointer to the object's space in RAM? Is that correct?
No, the constructor is not used to get a pointer.
The purpose of the constructor is to initialize all member variables when an object of this class is created. It initializes the object in memory.
The default constructor is the constructor that can be called with no arguments.
When you implement a class, you can implement your own default constructor to make it do what you want it to do.
When you do not provide any constructor for your class, the compiler will provide a default constructor for this class, but it will not initialize the members.
Default constructors are significant because they are automatically invoked in certain circumstances:
When an object value is declared with no argument list, e.g. MyClass x;; or allocated dynamically with no argument list, e.g. new MyClass or new MyClass(); the default constructor is used to initialize the object
When an array of objects is declared, e.g. MyClass x[10]; or allocated dynamically, e.g. new MyClass [10]; the default constructor is used to initialize all the elements
When a derived class constructor does not explicitly call the base class constructor in its initializer list, the default constructor for the base class is called
When a class constructor does not explicitly call the constructor of one of its object-valued fields in its initializer list, the default constructor for the field's class is called
In the standard library, certain containers "fill in" values using the default constructor when the value is not given explicitly, e.g. vector<MyClass>(10); initializes the vector with 10 elements, which are filled with the default-constructed value of our type.
In the above circumstances, it is an error if the class does not have a default constructor.
No. The constructor is not used to get a pointer. The constructor receives this pointer.
The constructor is used to initialize the object's space in RAM.
The default constructor does what you want it to do! I mean your can write your own default constructor for your class. This default constructor can initialize the memory, or leave it uninitialized, as you choose.
In the same vein, the implicit default constructor will be written automatically by the compiler to initialize the object RAM space. It will take care of initializing the non-static member variables of your class that do have default constructors. For example, if your class has a non-static std::string as member variable, then std::string default constructor will be called to initialize this variable. All non-static member variables of POD types (int, char, pointers,...) will not be initialized.
No.
MyClass obj; // Default construct
MyClass* obj2 = new MyClass; // Also default construct
In the first one, space for obj is first allocated, typically in the stack. The second one is allocated on the heap. The addresses where they reside are the ones that are passed to the proper constructor in these case.
The first-argument-is-the-this-pointer situation does not only apply to the default constructor, as a hidden this pointer is passed to all non-static class methods as their first arguments[1].
Then you probably know the rest. The constructor sets-up and initializes the object's members and states and any other things that needs to be done.
[1]Have you observed some examples like this?
my_type obj;
func_that_calls_a_callback(std::bind(&my_type::method, &obj));
That demonstrates that the first parameter is a pointer to some object is bound to the first parameter of my_type::method. That becomes the this pointer which points, in this case, to obj.
So, basically, the constructor is used to get a pointer to the object's space in RAM? Is that correct?
No, that's just a consequence
How does the default constructor initialize that memory? Does it get initialized to zero?"
No: the default constructor is just a function. It does what what you define it to do.
It is normally designed to "initialize" the memory by assigning to the contained variables (the object member) a proper value or by calling in turn their own constructors.
Think to this:
class point
{
public:
int x,y; //< just two values
point() //< default constructor
{ x=0; y=0; } //< function body assigning values
};
or
class point
{
public:
int x,y; //< just two values
point() //< default constructor
:x(), y() //< member init-list explicitly calling contrutors
{} //< empty body
};
Note that, until you don't declare a variable of type point nothing will be executed.
int main()
{
point p; //< p created and point::point() called using p as *this
p.x=5; //< x member of p changed
return 0; //just exit main (jumps to the closing } )
} //< p destructor called here, using p as *this.
As per the "implicit default constructor", what it does is just:
call the bases implicit default constuctors
call the members implicit
default contructors.
For all class-based types, decaring a default ctor in fact replaces the implicit one, but -for "built-in types" (like int, char, float etc.)- the default explicit constructor -in fact- sets the value to zero, but the implicit one does nothing, thus letting the value uninitialized. (the implementations can use different techniques to come to this same result)

Calling method of not yet constructed object

Having a simple class:
class A {
public:
A() {}
void set(int value) { value_ = value; }
private:
int value_;
};
and its global instance:
A a;
Is it OK to call method set on a not yet constructed object a? That can happen when for example a.set(123) is called from a constructor of another global object in another translation unit.
Will the value in the object a set by calling a.set(123) remain when the non-parametric and empty constructor of A is later called for object a?
Is it ok to call method set on a not yet constructed object a?
No. You may not call member functions for an object that has not yet begun construction.
(Since the answer is no, your second question requires no answer.)
If you may need to access this global instance from multiple translation units during dynamic initialization, you can use the Meyers singleton technique:
A& global_a()
{
static A a;
return a;
}
a will be initialized when global_a() is first called. Note that in a multithreaded program you may need to concern yourself with synchronization of the initialization.
When you write
A a;
a is a constructed object now. In case A is a then A default constructor was already been called
If in 1) you mean it's ok to call set in the constructor, then yes, that's fine because it isn't a virtual method. You cannot call a virtual method in the constructor.
As for 2), what you're asking isn't really clear. The constructor is only called once (although there are ways around that sort of thing, but don't do them) and that is when the object is first created. You can't call the constructor on a a second time so the question doesn't really make sense.