You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++分段函数初始化问题:局部对象超作用域致未定义行为

Great catch on the undefined behavior—you're exactly right about the dangling pointers from local LinearFunction objects going out of scope. Let's fix this properly so you can handle up to 20 points (or more) without issues.

The Root Problem

When you create auto f = LinearFunction(...) inside the loop, that object lives only for the duration of the loop iteration. Storing a pointer to it in the map means once the loop moves on, that pointer points to garbage memory. Accessing it later leads to the weird output you saw.

Fixed Solution: Store Copies Instead of Pointers

The simplest and safest fix is to store actual LinearFunction objects in your map instead of pointers. Since each LinearFunction only holds two doubles (slope and intercept), this is incredibly memory-efficient even for 20 points (19 segments total). Here's the revised code:

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>

struct Point { double x; double y; };

class LinearFunction {
public:
    LinearFunction(const Point &A, const Point &B) {
        double den = A.x - B.x;
        m = (A.y - B.y) / den;
        c = (A.x * B.y - A.y * B.x) / den;
    }

    // Marked const since evaluating doesn't modify the function
    double operator()(double x) const { 
        return m * x + c; 
    }

private:
    double m = 0;
    double c = 0;
};

class PiecewiseFunction {
public:
    // Take points by value so we can sort them safely without modifying the original
    explicit PiecewiseFunction(std::vector<Point> points) {
        // Critical: sort points by x-coordinate to ensure valid, non-overlapping segments
        std::sort(points.begin(), points.end(), [](const Point& a, const Point& b) {
            return a.x < b.x;
        });

        for (size_t i = 0; i < points.size() - 1; ++i) {
            // Insert a copy of the LinearFunction directly into the map
            fns.emplace(
                std::make_pair(points[i].x, points[i+1].x),
                LinearFunction(points[i], points[i+1])
            );
        }
    }

    double operator()(double x) const {
        // Find the segment where x falls in [lb, ub)
        auto iter = std::find_if(fns.cbegin(), fns.cend(), [x](const auto &entry) {
            const auto& bounds = entry.first;
            return x >= bounds.first && x < bounds.second;
        });

        if (iter == fns.end()) {
            // Handle out-of-bounds cases (adjust this to your needs: throw, return NaN, etc.)
            return 0.0;
        }

        // Call the stored LinearFunction directly (no pointer dereferencing needed!)
        return iter->second(x);
    }

private:
    // Store copies of LinearFunction instead of pointers
    std::map<std::pair<double, double>, LinearFunction> fns;
};

int main() {
    // Test the original case
    std::vector<Point> points {{0,0}, {0.5,1}, {1,0}};
    PiecewiseFunction f{points};
    std::cout << "x = 0.5; f(x) = " << f(0.5) << std::endl; // Outputs 1.0 as expected

    // Test with 20 points (linear function y=2x)
    std::vector<Point> manyPoints;
    for (int i = 0; i < 20; ++i) {
        manyPoints.push_back({static_cast<double>(i), static_cast<double>(i*2)});
    }
    PiecewiseFunction f20{manyPoints};
    std::cout << "x = 15.3; f(x) = " << f20(15.3) << std::endl; // Outputs 30.6

    return 0;
}

Key Improvements

  1. No More Dangling Pointers: By storing copies of LinearFunction, each segment's function persists for the lifetime of the PiecewiseFunction object.
  2. Sorted Points: Added sorting to ensure input points are in order of increasing x—this prevents invalid overlapping segments if someone passes unsorted points.
  3. Const-Correctness: Marked operator() as const since evaluating the function doesn't modify its state, making the code safer and more idiomatic.
  4. Efficient Insertion: Used emplace to construct LinearFunction objects directly in the map, avoiding unnecessary copies.

Alternative: Smart Pointers (If You Prefer Heap Allocation)

If you need to use heap allocation (e.g., for more complex function types later), you can use std::unique_ptr to manage memory safely:

// Inside PiecewiseFunction's private section:
std::map<std::pair<double, double>, std::unique_ptr<LinearFunction>> fns;

// In the constructor:
for (size_t i = 0; i < points.size() - 1; ++i) {
    fns.emplace(
        std::make_pair(points[i].x, points[i+1].x),
        std::make_unique<LinearFunction>(points[i], points[i+1])
    );
}

// In operator():
return (*iter->second)(x);

This works because unique_ptr takes ownership of the heap-allocated LinearFunction and automatically cleans it up when the map is destroyed—no more manual memory management!

内容的提问来源于stack exchange,提问作者Oleg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:38:00