惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hugging Face - Blog
Hugging Face - Blog
量子位
H
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
MongoDB | Blog
MongoDB | Blog
小众软件
小众软件
爱范儿
爱范儿
博客园 - 【当耐特】
Vercel News
Vercel News
S
SegmentFault 最新的问题
M
MIT News - Artificial intelligence
F
Fortinet All Blogs
Apple Machine Learning Research
Apple Machine Learning Research
GbyAI
GbyAI
博客园 - 叶小钗
博客园_首页
V
Visual Studio Blog
宝玉的分享
宝玉的分享
B
Blog
MyScale Blog
MyScale Blog
C
Check Point Blog
博客园 - 三生石上(FineUI控件)
L
LangChain Blog
V
V2EX

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Beyond New and Delete: Engineering Approach with gsl::own...
Rui-Tech · 2026-04-26 · via DEV Community

Rui-Tech

In my previous articles, Beyond new and delete: A Practical Guide to Refactoring Raw Pointers to Smart Pointers and Beyond new and delete: to Weak Pointer, I explained how to refactor raw pointers into unique_ptr, shared_ptr, weak_ptr, and references.

But swapping pointer types is only half the battle. A successful refactoring also requires a systematic engineering process — one that combines ownership analysis, modern C++ types, static analysis, and incremental testing to ensure safety and correctness.

In this article, we focus on that engineering workflow:
Audit & AnnotateStatic AnalysisReplaceRefactor Incrementally

Step Action
1 Audit & Annotate – Mark owning vs observer pointers, use GSL
2 Static Analysis – Enable -Wall, run clang-tidy, add sanitizers
3 Replace with Modern Typesunique_ptr, shared_ptr, span, references
4 Refactor Incrementally – Start with leaf modules, remove manual delete

Step 1. Audit and Annotate Ownership

Goal: Make ownership explicit before changing any code.

Use comments or annotations to mark which pointers own memory and which do not.

Consider using the Guidelines Support Library (GSL) – available via vcpkg, Conan, or as a header‑only library (#include <gsl/gsl>):

  • gsl::owner<T*> for owning pointers.
  • T* or gsl::not_null<T*> for non-owning pointers.

Example:

#include <gsl/gsl>

void process(gsl::not_null<MyClass*> ptr) {
    // ptr is guaranteed non-null - no need to check!
    ptr->doSomething();
}

void legacy_owner(gsl::owner<MyClass*> owned) {
    // This raw pointer OWNS the memory
    delete owned;
}

Enter fullscreen mode Exit fullscreen mode

Step 2. Use Static Analysis and Compiler Options

Enable compiler warnings for unsafe pointer usage:

  • GCC/Clang: -Wall -Wextra -Werror

  • MSVC: /W4

or Use static analysis tools to catch raw pointer misuse:

  • clang-tidy

  • Cppcheck

# Run clang-tidy with Core Guidelines checks
clang-tidy --checks='cppcoreguidelines-owning-memory,modernize-*' file.cpp 

Enter fullscreen mode Exit fullscreen mode

Other useful tools: LeakSanitizer, Valgrind, Dr. Memory.

Typical warnings are listed below.

Warning 1: Missing 'gsl::owner' on allocated pointer

int* data = new int[100];  // warning here
delete[] data;

Enter fullscreen mode Exit fullscreen mode

warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>' [cppcoreguidelines-owning-memory]

Enter fullscreen mode Exit fullscreen mode

Fix: gsl::owner<int*> data = new int[100]; or use std::unique_ptr.

Warning 2: Deleting a non-owner pointer

int* ptr = new int(42);  // missing owner annotation
delete ptr;              // warning here

Enter fullscreen mode Exit fullscreen mode

warning: deleting a pointer through a type that is not marked 'gsl::owner<>' [cppcoreguidelines-owning-memory]

Enter fullscreen mode Exit fullscreen mode

Fix: Mark with gsl::owner or use smart pointer.

Warning 3: Returning raw pointer from factory (ownership unclear)

int* make_int() {        // warning: returning raw pointer
    return new int(42);
}

Enter fullscreen mode Exit fullscreen mode

warning: function returns a raw pointer that may be an owner [cppcoreguidelines-owning-memory]

Enter fullscreen mode Exit fullscreen mode

Fix: std::unique_ptr<int> make_int() or mark as gsl::owner<int*>.

Warning 4: Assignment loses ownership

gsl::owner<int*> create() { return new int(42); }

void test() {
    int* p = create();   // warning: owner assigned to non-owner
    delete p;
}

Enter fullscreen mode Exit fullscreen mode

warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>' [cppcoreguidelines-owning-memory]

Enter fullscreen mode Exit fullscreen mode

Fix: gsl::owner<int*> p = create(); or use auto p = create();.

Warning 5: Using std::unique_ptr with raw delete

auto p = std::make_unique<int>(42);
delete p.get();          // warning: manual delete on smart pointer

Enter fullscreen mode Exit fullscreen mode

warning: 'delete' applied to pointer that is owned by a smart pointer [cppcoreguidelines-owning-memory]

Enter fullscreen mode Exit fullscreen mode

Fix: Remove manual delete – the smart pointer handles it.

Step 3. Replace with Modern Types

Ownership/Usage Modern C++ Type Notes
Sole ownership std::unique_ptr<T> Use std::make_unique<T>()
Shared ownership std::shared_ptr<T> Use std::make_shared<T>()
Non-owning, never null T& or gsl::not_null<T*> Prefer references when possible
Non-owning, may be null T* (with optional GSL annotation) Raw pointer is fine as an observer
Array/view, non-owning std::span<T> C++20 (or GSL span for older standards)

Example:

void process(std::span<int> data); // Non-owning view over array/vector

Enter fullscreen mode Exit fullscreen mode

💡 For dynamic arrays, consider std::vector<T> over std::unique_ptr<T[]> unless you need a specific allocator or C API compatibility.

Step 4. Refactor Incrementally

Start with leaf modules (fewest dependencies).

  • Replace gsl::owner<T*> with std::unique_ptr<T> or std::shared_ptr<T> as appropriate.
  • Use std::span<T> for functions that take raw array pointers and sizes.
  • Update function signatures and member variables.
  • Remove manual delete calls.

An Example: Step‑by‑Step Refactoring

Before:

void foo(int* arr, size_t n);               // arr is not owned
void bar(gsl::owner<MyClass*> obj);         // obj is owned

void caller() {
    int* data = new int[10];
    foo(data, 10);
    delete[] data;

    MyClass* mc = new MyClass();
    bar(mc);
    delete mc;
}

Enter fullscreen mode Exit fullscreen mode

After:

#include <memory>
#include <span>

void foo(std::span<int> arr);                // Non-owning view
void bar(std::unique_ptr<MyClass> obj);      // Ownership transferred

void caller() {
    auto data = std::make_unique<int[]>(10);
    foo(std::span<int>(data.get(), 10));
    // No delete needed

    auto mc = std::make_unique<MyClass>();
    bar(std::move(mc));
    // No delete needed
}

Enter fullscreen mode Exit fullscreen mode

When NOT to Refactor

Refactoring raw pointers isn't always the right move. Consider postponing or skipping when:

  • Performance‑critical hot paths – the (small) overhead of smart pointers might matter (measure first).
  • Codebases frozen for certification – aviation, medical, or safety‑critical systems.
  • Interfacing with C libraries – raw pointers are often unavoidable there.
  • The code is about to be deprecated – don't invest time in dead code.

Reference: clang-tidy Commands for Raw Pointer Refactoring

Check Commands (Analyze Only)

Command Purpose
clang-tidy --checks='cppcoreguidelines-owning-memory' file.cpp Detect missing gsl::owner annotations and improper deletions
clang-tidy --checks='modernize-make-unique' file.cpp Find raw new that can be replaced with std::make_unique
clang-tidy --checks='modernize-make-shared' file.cpp Find raw new that can be replaced with std::make_shared
clang-tidy --checks='modernize-use-auto' file.cpp Find verbose type names that can be replaced with auto
clang-tidy --checks='modernize-use-nullptr' file.cpp Find NULL or 0 that can be replaced with nullptr
clang-tidy --checks='cppcoreguidelines-owning-memory,modernize-*' file.cpp Run all relevant checks together

Fix Commands (Apply Changes)

Command Purpose
clang-tidy --fix --checks='modernize-make-unique' file.cpp Automatically replace new with std::make_unique
clang-tidy --fix --checks='modernize-make-shared' file.cpp Automatically replace new with std::make_shared
clang-tidy --fix --checks='modernize-use-auto' file.cpp Automatically replace verbose types with auto
clang-tidy --fix --checks='modernize-use-nullptr' file.cpp Automatically replace NULL with nullptr
clang-tidy --fix --checks='cppcoreguidelines-owning-memory' file.cpp Add gsl::owner annotations (manual review still recommended)

Recommended Workflow with clang-tidy

# Step 1: Run checks to see what needs fixing
clang-tidy --checks='cppcoreguidelines-owning-memory,modernize-*' file.cpp

# Step 2: Apply automatic fixes safely
clang-tidy --fix --checks='modernize-make-unique,modernize-make-shared,modernize-use-auto,modernize-use-nullptr' file.cpp

# Step 3: Re-run checks to verify fixes
clang-tidy --checks='cppcoreguidelines-owning-memory' file.cpp

Enter fullscreen mode Exit fullscreen mode

Conclusion

A professional refactoring from raw pointers to modern C++ involves:

  • Explicitly annotating ownership (with GSL or comments)
  • Using compiler warnings and static analysis
  • Replacing with the right smart pointer or view type (unique_ptr, shared_ptr, std::span, references)
  • Testing and reviewing at every step

This approach produces safer, more maintainable, and truly modern C++ code – without the sleepless nights hunting for memory leaks.