use std::shared_ptr instead of raw ptr