shared pointer

I'm trying to use shared pointer in my code as follows,

1
2
3
4
5
6
7
8
enum BoundaryType {

	PressureInlet,
	PressureOutlet,
	VelocityInlet,
	VelocityOutlet,
	ZouHe
};


1
2
3
4
5
6
7
8
9
10
11
void Domain::CreateInletBoundaryType(Type type) {

	for (int coord_z = 0; coord_z < domainSize_[2]; coord_z++)
	{
		for (int coord_y = 0; coord_y < domainSize_[1]; coord_y++)
		{
			lattice_.push_back(std::make_shared<type>(0, coord_y, coord_z));

		}
	}
}


the code crushes in this line, lattice_.push_back(std::make_shared<type>(0, coord_y, coord_z));

Does anyone know why I'm getting this error?
I can use make_shared with any object but type which is enum.
Last edited on
It's difficult to say without a complete example.

I don't see BoundaryType being used anywhere in the second snippet.

Is `type` on line 7 meant to be `Type`? (I don't see how the code could compile otherwise)

Is domainSize_[2] within bounds? (i.e. is the size of domainSize_ at least 3?)
Last edited on
Thanks for the answer. Actually that's a mistake in this version of code which I made as a question, it should be BoundaryType, not Type. Still it doesn't compile. domainsize_ is a vector containing the Nx,Ny and Nz. For example domainsize_={20,30,40}. This is a complex code and I can't make an example to reflect what I mean exactly. In my problem I have different type of boundary and I'm trying to have that feature to change the boundary type whenever user desires apply different boundary condition. Each of These boundary condition are a class and I want to have an object of these classes as a shared pointer.
I changed Type to BoundaryType,

1
2
3
4
5
6
7
8
9
10
11
void Domain::CreateInletBoundaryType(BoundaryType type) {

	for (int coord_z = 0; coord_z < domainSize_[2]; coord_z++)
	{
		for (int coord_y = 0; coord_y < domainSize_[1]; coord_y++)
		{
			lattice_.push_back(std::make_shared<type>(0, coord_y, coord_z));

		}
	}
}
Last edited on
Cplusc wrote:
Still it doesn't compile.

Ah, so it didn't even compile? When you said "the code crushes" I thought you meant that the program crashed (at runtime).

It's always useful to include the error message when asking for help if there is one, especially if you don't provide a complete example that can be used to reproduce the error.

Cplusc wrote:
This is a complex code and I can't make an example to reflect what I mean exactly.

For compile-time errors it might not be necessary but for runtime problems it's often a good idea to try and create a "minimal reproducible example".
https://en.wikipedia.org/wiki/Minimal_reproducible_example

It might involve a bit of work but it makes it easier for us to help you and chances are great that you'll find the problem yourself in the process.

Cplusc wrote:
In my problem I have different type of boundary and I'm trying to have that feature to change the boundary type whenever user desires apply different boundary condition. Each of These boundary condition are a class and I want to have an object of these classes as a shared pointer.

Not sure I understand exactly, but if you have a class type that contains the BoundaryType, coord_y and coord_z then you probably want to store shared_pointers to such objects inside the lattice_ container.

Something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
enum BoundaryType {
	...
};

struct Boundary {
	BoundaryType type;
	int coord_y;
	int coord_z;
}

class Domain {
public:
	void CreateInletBoundaryType(BoundaryType);
private:
	std::vector<std::shared_ptr<Boundary>> lattice_;
}

void Domain::CreateInletBoundaryType(BoundaryType type) {
	...
	lattice_.push_back(std::make_shared<Boundary>(type, coord_y, coord_z)); // Before C++20 Boundary would need a Boundary(BoundaryType, int, int) constructor for this to compile
	...
}
Last edited on
Thanks for your detailed answer.
I'm not sure whether you're familiar with lattice boltzmann method or not, but let's explain what I'm doing in the code. In class Domain, I have a friend class named node. node is actually where the lattice, its coordinate, neighbors, equilibrium variable, streaming will be constructed and also has a member function for boundary condition which is virtual. I have different classes for different boundary condition which are inherited from class node. Then each one of these classes have a member function for boundary condition to overwrite the boundary condition base class,node. I hope I could've made my point.
Last edited on
Okay, maybe I see what you tried to do here...

Did you hope this:
1
2
BoundaryType type = PressureInlet;
lattice_.push_back(std::make_shared<type>(0, coord_y, coord_z));
would be equivalent to this:
 
lattice_.push_back(std::make_shared<PressureInlet>(0, coord_y, coord_z));
assuming there is a class named PressureInlet?

The bad news is that this is not possible. Things like this might be possible in some scripting languages but not in C++.

The thing you pass inside <> to std::make_shared has to be a type but the variable type is not actually a type. It's an object of type BoundaryType. There is no automatic mapping between the enumerator named PressureInlet and the class named PressureInlet. It's up to you to make that connection.

1
2
3
4
5
6
7
8
9
10
11
12
// Here I assume BoundaryType is declared as a scoped enumeration (enum class) to avoid
// name clashes between the enumerators and the class types with the same names.
BoundaryType type = BoundaryType::PressureInlet;
switch (type) {
	case BoundaryType::PressureInlet:
		lattice_.push_back(std::make_shared<PressureInlet>(0, coord_y, coord_z));
		break;
	case BoundaryType::PressureOutlet:
		lattice_.push_back(std::make_shared<PressureOutlet>(0, coord_y, coord_z));
		break;
	/* And so on, for all types... */
}

In general, the things inside <> are called template arguments. They are often types but can sometimes be values, in either case they need to be known at compile time. It's never possible to pass in a runtime value. That would be incompatible with how templates in C++ work.
Last edited on
What you described is exactly what I meant to do.

Did you hope this:
1
2
BoundaryType type = PressureInlet;
lattice_.push_back(std::make_shared<type>(0, coord_y, coord_z));

would be equivalent to this:


lattice_.push_back(std::make_shared<PressureInlet>(0, coord_y, coord_z));
assuming there is a class named PressureInlet?


Now I see why I can't do this in my code.
Thanks for the help.
Last edited on
@Peter87

Sorry again,
I didn't get how to fix the issue by following code,
1
2
3
4
5
6
7
8
9
10
BoundaryType type = BoundaryType::PressureInlet;
switch (type) {
	case BoundaryType::PressureInlet:
		lattice_.push_back(std::make_shared<PressureInlet>(0, coord_y, coord_z));
		break;
	case BoundaryType::PressureOutlet:
		lattice_.push_back(std::make_shared<PressureOutlet>(0, coord_y, coord_z));
		break;
	/* And so on, for all types... */
}


The following piece of code will specify what kind of boundary condition will be applied on the inlet node. now it's ZouHe, it may change to any other type of boundary. I just didn't get how above code can do this.

1
2
3
4
5
6
7
8
9
10
11
12
void Domain::CreateInletBoundaryType(BoundaryType type) {


	for (int coord_z = 0; coord_z < domainSize_[2]; coord_z++)
	{
		for (int coord_y = 0; coord_y < domainSize_[1]; coord_y++)
		{
			lattice_.push_back(std::make_shared<ZouHe>(0, coord_y, coord_z));

		}
	}
}
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
void Domain::CreateInletBoundaryType(BoundaryType type) {
    for (int coord_z = 0; coord_z < domainSize_[2]; coord_z++){
        for (int coord_y = 0; coord_y < domainSize_[1]; coord_y++){
            switch (type){
                //...
                case BoundaryType::ZouHe:
                    lattice_.push_back(std::make_shared<ZouHe>(0, coord_y, coord_z));
                //...
            }
        }
    }
}

Although usually what you'd really want is for the dynamic constructor to be a part of the base class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#define HANDLE_BOUNDARY_TYPE(T)             \
    case BoundaryType::T:                   \
        return std::make_unique<T>(x, y, z)

//static function
std::unique_ptr<Boundary> Boundary::create(BoundaryType type, int x, int y, int z){
    switch (type) {
        HANDLE_BOUNDARY_TYPE(PressureInlet);
        HANDLE_BOUNDARY_TYPE(PressureOutlet);
        HANDLE_BOUNDARY_TYPE(VelocityInlet);
        HANDLE_BOUNDARY_TYPE(VelocityOutlet);
        HANDLE_BOUNDARY_TYPE(ZouHe);
    }
    throw std::exception();
}

void Domain::CreateInletBoundaryType(BoundaryType type) {
    for (int coord_z = 0; coord_z < domainSize_[2]; coord_z++){
        for (int coord_y = 0; coord_y < domainSize_[1]; coord_y++){
            lattice_.push_back(Boundary::create(type, 0, coord_y, coord_z));
        }
    }
}
thanks for your help.
Last edited on
Topic archived. No new replies allowed.